我试图在ASP.Net Core应用程序中使用Dapper将多个表映射到一个对象,其他对象作为其属性。
我的表格如下(只是基本摘要):
address_type表(查找表)
phone_number表(没有用户ID存储在此表中,此表只是电话记录)
基本上,如果所有用户都没有地址或电话记录,或者只有列表中的第一个用户有地址/电话记录,那么结果会被恢复正常。我想要的是如果用户有地址/电话号码然后填写该字典,否则我仍然想要所有用户信息但该地址/电话号码字典将为空。
我的对象如下所示:
public class User
{
public uint id { get; set; }
public DateTime modified_date { get; set; }
public uint modified_by { get; set; }
public string user_name { get; set; }
public uint company_code { get; set; }
public string email { get; set; }
public bool active { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public Dictionary<uint, Address.Address> addresses { get; set; }
public Dictionary<uint, Address.PhoneNumber> phone_numbers { get; set; }
}
public class Address
{
public uint address_id { get; set; }
public AddressType address_type { get; set; }
public string address_line1 { get; set; }
public string address_line2 { get; set; }
public string address_line3 { get; set; }
public string city { get; set; }
public string state { get; set; }
public string country_code { get; set; }
public string postal_code { get; set; }
public sbyte is_po_box { get; set; }
}
public class AddressType
{
public uint id { get; set; }
public string name { get; set; }
}
public class PhoneNumber
{
public uint id { get; set; }
public PhoneNumberType phone_number_type { get; set; }
public string phone_number { get; set; }
public string phone_ext { get; set; }
}
public class PhoneNumberType
{
public uint id { get; set; }
public string name { get; set; }
}
这是我的函数,我尝试使用Dapper映射到User类:
public List<User> GetUsersByStatus(uint companyCode, string status)
{
if (companyCode == 0)
throw new ArgumentOutOfRangeException("companyID", "The Company ID cannot be 0.");
List<User> Users = new List<User>();
try
{
string sql = @"SELECT u.*, ad.*, adt.*, p.*, pt.*
FROM master.user u
LEFT JOIN master.user_has_address AS uha ON uha.user_id = u.id
LEFT JOIN master.address AS ad ON ad.id = uha.address_id
LEFT JOIN master.lookup_address_type adt ON adt.id = uha.address_type_id
LEFT JOIN master.user_has_phone_number AS uhp ON uhp.user_id = u.id
LEFT JOIN master.phone_number AS p ON p.id = uhp.phone_number_id
LEFT JOIN master.lookup_phone_number_type pt ON pt.id = uhp.phone_number_type_id
WHERE u.company_code = " + companyCode;
switch (status)
{
case "1":
// Active Status.
sql = sql + " AND (u.active = TRUE)";
break;
case "2":
// Retired Status.
sql = sql + " AND (u.active = FALSE)";
break;
}
sql = sql + " ORDER BY u.user_name";
using (var conn = new MySqlConnection(connectionString))
{
conn.Open();
var userDictionary = new Dictionary<uint, User>();
conn.Query<User, Address, AddressType, PhoneNumber, PhoneNumberType, User>(sql, (u, ad, adt, p, pt) =>
{
User user;
if (!userDictionary.TryGetValue(u.id, out user))
userDictionary.Add(u.id, user = u);
if (ad != null && adt != null)
{
Address address = ad;
address.address_type = new AddressType() { id = adt.id, name = adt.name };
if (user.addresses == null)
user.addresses = new Dictionary<uint, Address>();
if (!user.addresses.ContainsKey(adt.id))
user.addresses.Add(adt.id, address);
}
if (p != null && pt != null)
{
PhoneNumber phone = p;
phone.phone_number_type = new PhoneNumberType() { id = pt.id, name = pt.name };
if (user.phone_numbers == null)
user.phone_numbers = new Dictionary<uint, PhoneNumber>();
if (!user.phone_numbers.ContainsKey(pt.id))
user.phone_numbers.Add(pt.id, phone);
}
return user;
},
splitOn: "id,id,id,id").AsQueryable();
Users = userDictionary.Values.ToList();
}
}
catch(Exception ex)
{
//TO DO: log exception
}
return Users;
}
我试过跟踪它并且在第三个用户(例如)有地址/电话记录的情况下,它似乎抓住了前2个用户,但是当它到达带有地址的记录时跳出查询部分/电话号码然后它返回一个空的用户列表。
有谁知道我做错了什么?
事实证明,主要的问题是我将Address_id参数保留在Address类中的名称,它应该只是'id'。我更新了它现在有效,我也根据Palle Due的建议更新了我的代码,所以也可能有所贡献。
我不确定这是解决方案,但我对此代码有疑问:
User user;
if (!userDictionary.TryGetValue(u.id, out user))
userDictionary.Add(u.id, user = u);
请记住,u是lambda的参数,并将在执行期间更改。我会这样做:
User user;
if (!userDictionary.TryGetValue(u.id, out user))
{
user = new User(u); // Make a new instance of user
userDictionary.Add(u.id, user);
}
您还应该使用查询参数:
WHERE u.company_code = @CompanyCode";
最后,我认为构建用于保存地址和电话号码的字典不应该由此代码负责。 User构造函数应该处理这个问题。