在LINQ中设置DefaultIfEmpty方法的默认值(当默认值具有多个关系时)?

在LINQ中设置DefaultIfEmpty方法的默认值(当默认值具有多个关系时)?,linq,entity-framework-6,Linq,Entity Framework 6,我有三个目标: 事件(关系:有许多EventProducts) 产品(关系:有许多EventProducts) EventProduct(关系:对于多个事件,对于多个产品,具有销售数量、分配数量等属性,这些属性应存储在每个产品和每个事件中) 在我的应用程序中,当有人单击某个事件时,一个新窗口将初始化为所有产品的列表。从那里,他们可以修改我需要的单元格,以便在WPF中填充数据网格,这样当有人单击事件时。因此,在这段代码的上下文中,事件是已知的且恒定的 我遇到的问题是如何创建EventProduct

我有三个目标:

  • 事件(关系:有许多EventProducts)

  • 产品(关系:有许多EventProducts)

  • EventProduct(关系:对于多个事件,对于多个产品,具有销售数量、分配数量等属性,这些属性应存储在每个产品和每个事件中)

  • 在我的应用程序中,当有人单击某个事件时,一个新窗口将初始化为所有产品的列表。从那里,他们可以修改我需要的单元格,以便在WPF中填充数据网格,这样当有人单击事件时。因此,在这段代码的上下文中,事件是已知的且恒定的

    我遇到的问题是如何创建EventProduct的默认类型

    我需要的是有一个查询,如果数据库中没有EventProduct,它将用
    EventProduct.Event=currentEvent
    实例化一个EventProduct(使用此查询创建的所有EventProducts的currentEvent都将是常量)和
    EventProduct.Product=Product
    (每行的Product都将更改)

    当数据库中存在关联的EventProduct时,此代码运行良好。但是如果没有,我的选择返回的产品很好,但是整个EventProduct为空

    var query2 = from product in dbContext.Products
                 join eventProduct in dbContext.EventProducts
                     on new { pIndex = product.index, eIndex = currentEvent.index }
                     equals new { pIndex = eventProduct.Product.index, eIndex = eventProduct.Event.index } into temp
                 from eventProduct in temp.DefaultIfEmpty() // this is my problem line
                 select new { 
                        Product = product,
                        EventProduct = eventProduct
                  };
    
    我曾尝试为
    EventProduct(Event e,Product p)
    创建一个构造函数,并在
    DefaultIfEmpty()
    方法中将值传递给构造函数,但我发现错误,我的构造函数必须有0个参数才能以这种方式使用。我不能这样做,因为如果我这样做,就无法告诉我的EventProduct()对象它应该与哪个事件和产品关联

    我也没有尝试过构造函数,只是创建了一个新的EventProduct并设置了它的属性,但是我得到了错误“实体或复杂类型…EventProduct不能在LINQ to Entites查询中构造”

    在最终结果中,我想选择我的
    产品
    事件产品
    。如果没有与该
    Product
    Event
    关联的
    EventProduct
    ,则我的EventProduct选择应设置为默认值,其中currentEvent、当前行的Product和所有属性都设置为默认值(在本例中均为小数,并且应为0)

    编辑:我刚刚尝试了此查询,它还提供了一个不受支持的错误:

    var query2 = from product in dbContext.Products
                 join eventProduct in dbContext.EventProducts
                     on new { pIndex = product.index, eIndex = currentEvent.index }
                     equals new { pIndex = eventProduct.Product.index, eIndex = eventProduct.Event.index } into temp
                 from eventProduct in temp.DefaultIfEmpty()
                 select new { 
                     Product = product,
                     EventProduct = eventProduct != null ?
                     eventProduct : new EventProduct
                     {
                         Product = product,
                         Event = currentEvent,
                         quantity_allocated = 0,
                         quantity_sold = 0,
                         quantity_sampled = 0
                     }
                 };
    
    编辑:使用此技术解决:

    1) 创建对象,因为匿名对象是只读的:

        class Associations
        {
            public class ProductEventProduct
            {
                public Product Product { get; set; }
                public EventProduct EventProduct { get; set; }
            }
        }
    
    2) 数据集中的Foreach空对象,替换为默认对象

    var query = from product in dbContext.Products
                             join eventProduct in dbContext.EventProducts
                                 on new { pIndex = product.index, eIndex = currentEvent.index }
                                    equals new { pIndex = eventProduct.Product.index, eIndex = eventProduct.Event.index } into temp
                             from eventProduct in temp.DefaultIfEmpty()
                             select new Associations.ProductEventProduct { 
                                 Product = product,
                                 EventProduct = eventProduct
                             };
                var dataSource = query.ToList();
    
                foreach (Associations.ProductEventProduct entry in dataSource)
                {
                    if (entry.EventProduct == null)
                    {
                        entry.EventProduct = new EventProduct
                        {
                            Product = entry.Product,
                            Event = currentEvent,
                            quantity_allocated = 0,
                            quantity_sold = 0,
                            quantity_sampled = 0
                        };
                    }
                }
    

    您遇到的问题似乎是,您要求EntityFramework创建一个查询,但它不知道如何创建

    请记住,Linq使用延迟执行,因此当您编写查询时,它只是一个占位符,说明在哪里以及如何获取数据,而不是实际数据。直到其他一些代码请求数据时,查询才会实际运行并填充您的信息

    对于LINQtoEntities,这意味着它将用DB语言构建一个查询,并一直保持查询,直到您需要数据,然后在调用时通过您使用的任何DB提供程序按预期执行查询,并将其存储在内存中以供使用

    因此,当您试图在查询中构造一个新的
    EventProduct
    来填充空值时,DB不知道这是什么,您会得到错误,因为您仍然处于DB负责对象的查询部分。DB提供程序不知道如何构造新对象,因此EF无法转换查询,因此您会得到错误

    解决方案是,在尝试构造新的EventProduct之前,通过调用
    ToList()
    ToArray
    或类似命令来运行无EventProduct构造函数的查询,从而在此时强制运行查询,从而“水合”信息。 然后,在数据水合(在内存中)后,检查您在查询中创建的所有对象,如果
    EventProduct
    为空,则构建一个新对象并动态添加它,不管您想怎么做。(第二个查询可能包含Select语句?)

    我有点不了解您的原始查询(生成匿名对象)是否会被DBContext跟踪,但请记住这一点,并对其进行测试。如果添加一组绑定到这些匿名对象的
    EventProduct
    实例,则默认情况下可以在跟踪中包含这些实例,并且调用
    SaveChanges()
    可能会在无意中将它们全部写入数据库。要记住的东西


    希望这有帮助,让我知道

    您遇到的问题似乎是,您要求Entity Framework创建一个查询,但它不知道如何创建该查询

    请记住,Linq使用延迟执行,因此当您编写查询时,它只是一个占位符,说明在哪里以及如何获取数据,而不是实际数据。直到其他一些代码请求数据时,查询才会实际运行并填充您的信息

    对于LINQtoEntities,这意味着它将用DB语言构建一个查询,并一直保持查询,直到您需要数据,然后在调用时通过您使用的任何DB提供程序按预期执行查询,并将其存储在内存中以供使用

    因此,当您试图在查询中构造一个新的
    EventProduct
    来填充空值时,DB不知道这是什么,您会得到错误,因为您仍然处于DB负责对象的查询部分。DB提供程序不知道如何构造新对象,因此EF无法转换查询,因此您会得到错误

    解决的办法是在你试图欺骗之前先“补充”你的信息
    ......
    select new 
    { 
        Product = product,
        EventProduct = eventProduct != null 
            ? eventProduct 
            : new EventProduct { .... set default values}
    }
    
    select new 
    { 
        Product = product,
        EventProduct = new 
        {
             Product = product,
             EventId = currentEvent.Id, // possibly you will need to copy every field by hand 
             quantity_allocated = eventProduct == null ? 0 : eventProduct .quantity_allocated ,
             ....
        }
    }
    
    var query2 = from product in dbContext.Products
             join eventProduct in dbContext.EventProducts
                 on new { pIndex = product.index, eIndex = currentEvent.index }
                 equals new { pIndex = eventProduct.Product.index, eIndex = eventProduct.Event.index } into temp
             from eventProduct in temp.DefaultIfEmpty()
             select new { 
                 Product = product,
                 EventProduct = eventProduct
             };
    var results = query2.ToList();
    foreach(var r in results)
    {
          r.EventProduct = r.EventProduct != null 
                ? r.EventProduct 
                : new EventProduct { .... set default values}
    }