将联接结果选择为结果的问题

时间:2019-01-08 23:18:51

标签: c# entity-framework

我是EF的新手。为了简化起见,可以说直到最近,我有一个像这样的表

CREATE TABLE customer
(
    CustomerNumber int,
    CustomerName nvarchar(100)
)

我有一堂课来解决这个问题

[Table("customer")]
public class Customer
{
    [Key]
    public int CustomerNumber { get; set; }
    public string CustomerName { get; set; }
}

具有上下文:

public class MyContext : DbContext
    {
        public MyContext()
                : base("name=MyContext")
        {
        }

        public DbSet<Customer> Customers { get; set; }

    }

使用控制器:

public class CustomersController : ODataController
    {
        MyContext db = new MyContext();

        private bool CustomerExists(string key)
        {
            return db.Customers.Any(p => p.CustomerNumber == key);
        }

        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }

        [EnableQuery(PageSize =20)]
        public IQueryable<Customer> Get()
        {
            db.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
            return db.Customers;
        }

        [EnableQuery]
        public SingleResult<Customer> Get([FromODataUri] string key)
        {
            IQueryable<Customer> result = db.Customers.Where(p => p.CustomerNumber == key);
            return SingleResult.Create(result);
        }

    }

最近我有一个要显示新数据的新表

CREATE TABLE customerDetails
(
    CustomerNumber int,
    Role nvarchar(20),
    ContactName nvarchar(30)
)

对于每个客户编号,customerDetails表中有2个条目,每个角色的角色各不相同,例如AB

我正在尝试做的是将以下查询的结果放入修改后的实体中

查询:

SELECT c.CustomerNumber, c.CustomerName, cc1.ContactName as A_Name, cc2.ContactName as B_Name
FROM customer as c
JOIN customerDetails as cc1 ON c.CustomerNumber = cc1.CustomerNumber AND cc1.Role = 'A'
JOIN customerDetails as cc2 ON c.CustomerNumber = cc2.CustomerNumber AND cc2.Role = 'B'

我修改了我的实体:

[Table("customer")]
public class Customer
{
    [Key]
    public int CustomerNumber { get; set; }
    public string CustomerName { get; set; }
    public string A_Name { get; set; }
    public string B_Name { get; set; }
}

已添加:

[Table("customerDetails")]
public class Customer
{
    [Key]
    public int CustomerNumber { get; set; }
    public string Role { get; set; }
    public string ContactName { get; set; }
}

并修改了控制器:

[EnableQuery(PageSize =20)]
        public IQueryable<Customer> Get()
        {
            db.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
            return from c in db.Customers
                   join cc1 in db.CustomerContacts.Where(e => e.Role == "A") on c.CustomerNumber equals cc1.CustomerNumber
                   join cc2 in db.CustomerContacts.Where(e => e.Role == "B") on c.CustomerNumber equals cc2.CustomerNumber
                   select c;
        }

但是它返回一个空集。如何在此处正确编写该select语句并填充修改后的Customer实体?

1 个答案:

答案 0 :(得分:1)

您的实体应反映您的总体表结构。给定一个具有CustomerDetails实体的Customer实体,并且在CustomerNumber上两者之间存在1-many关系,则我将这些实体定位为:

public class Customer
{
   public int CustomerNumber {get; set;}
   public virtual ICollection<CustomerDetails> CustomerDetails {get; set;}
}

public class CustomerDetails
{
   public int CustomerDetailId {get; set;}
   public string Role {get; set;}
   public int CustomerNumber {get; set;}
}

...并映射客户和客户详细信息。请注意,CustomerDetails将拥有自己的PK列,而不是CustomerNumber,因为对于单个客户,您可能拥有2倍的客户详细信息(角色A和角色B)

我建议不要将实体传递到您的视图,而应创建视图模型供视图使用,并使用.Select从您的实体中选择相关详细信息。这是最佳性能,它允许您格式化/展平数据以适合您的视图,并且比将整个实体图暴露给使用者更安全。

或者,如果您希望为客户使用一组特定的相关角色(可选),则customer表中的RoleACustomerDetailsId和RoleBCustomerDetailsId为int?,然后可以引用这些相关实体。