使用可以为空的复合外键进行关联修复时出现异常

时间:2011-02-16 15:18:43

标签: entity-framework poco

我遇到了Pocos和可以为空的外键的问题。 我有2个表(订单和产品),每个表都有一个复合主键(orderid,orderid2)和(productid,productid2) 我在两个表之间设置了一个0,1 .. *关联。 一个订单可以与0或1个产品相关。 一个产品有*与他有关的订单。

如何崩溃:

  • 使用CreateObject()创建新产品。
  • 将新产品添加到实体集。
  • 创建新订单usung CreateObject()。
  • 将新订单添加到实体集。

当我向产品的订单列表添加订单时,它会崩溃尝试修复关联(在新订单上设置产品导航属性)

CREATE TABLE [dbo].[Products](
    [productid] [int] IDENTITY(1,1) NOT NULL,
    [productid2] [int] NOT NULL,
    [productname] [nchar](10) NULL,
 CONSTRAINT [PK_Products] PRIMARY KEY CLUSTERED 
(
    [productid] ASC,
    [productid2] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE TABLE [dbo].[Orders](
    [orderid] [int] NOT NULL,
    [orderid2] [int] NOT NULL,
    [ordername] [nchar](10) NULL,
    [productid] [int] NULL,
    [productid2] [int] NULL,
 CONSTRAINT [PK_orders] PRIMARY KEY CLUSTERED 
(
    [orderid] ASC,
    [orderid2] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Entity model

崩溃的代码:

            var product = context.CreateObject<Products>();
            context.Products.AddObject(product);
            var order = context.CreateObject<Orders>();
            context.Orders.AddObject(order);

            product.Orders.Add(order);
            if (order.Product != product) Console.WriteLine("error");

例外:

System.Data.EntityException was unhandled
  Message=Unable to set field/property Product on entity type System.Data.Entity.DynamicProxies.Orders_A0290D8629F0336D278E5AEF2C0F2A91FF56726ED5E3A9FA668AC902696A8651. See InnerException for details.
  Source=System.Data.Entity
  StackTrace:
       at System.Data.Objects.Internal.PocoPropertyAccessorStrategy.SetNavigationPropertyValue(RelatedEnd relatedEnd, Object value)
       at System.Data.Objects.Internal.EntityWrapper`1.SetNavigationPropertyValue(RelatedEnd relatedEnd, Object value)
       at System.Data.Objects.DataClasses.EntityReference`1.AddToObjectCache(IEntityWrapper wrappedEntity)
       at System.Data.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper wrappedTarget, Boolean applyConstraints, Boolean addRelationshipAsUnchanged, Boolean relationshipAlreadyExists, Boolean allowModifyingOtherEndOfRelationship, Boolean forceForeignKeyChanges)
       at System.Data.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper wrappedEntity, Boolean applyConstraints)
       at System.Data.Objects.DataClasses.EntityCollection`1.Add(TEntity entity)
       at Proxies.CSharp.Program.Main(String[] args) in Program.cs:line 20
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: System.NullReferenceException
       Message=Object reference not set to an instance of an object.
       Source=Proxies.CSharp
       StackTrace:
            at Proxies.CSharp.Orders.FixupProduct(Products previousValue, Boolean skipKeys) in Orders.cs:line 134
            at Proxies.CSharp.Orders.set_Product(Products value) in Orders.cs:line 106
            at System.Data.Entity.DynamicProxies.Orders_A0290D8629F0336D278E5AEF2C0F2A91FF56726ED5E3A9FA668AC902696A8651.SetBasePropertyValue(String , Object )
            at lambda_method(Closure , Object , String , Object )
            at System.Data.Objects.Internal.EntityProxyFactory.TrySetBasePropertyValue(Type proxyType, String propertyName, Object entity, Object value)
            at System.Data.Objects.Internal.EntityProxyFactory.<>c__DisplayClass8.<CreateBaseSetter>b__7(Object entity, Object value)
            at System.Data.Objects.Internal.PocoPropertyAccessorStrategy.SetNavigationPropertyValue(RelatedEnd relatedEnd, Object value)

注意:它适用于entytobjects,它适用于自我跟踪实体,如果密钥不是复合的或不可为空的,它就可以工作。

我做错了什么或者它是一个真正的错误?

2 个答案:

答案 0 :(得分:6)

我必须更正poco TT:更改线条(381,441和475):

<#=code.Escape(dependentProperty)#> = <#=code.Escape(navProperty)#>.<#=code.Escape(principalProperty)#>;

行:

<#=code.FieldName(dependentProperty)#> = <#=code.Escape(navProperty)#>.<#=code.Escape(principalProperty)#>;

答案 1 :(得分:0)

我假设你正在使用this poco实体generotor,或做一些类似的关系修复。如果是这样,那就是一个错误而且你做错了什么(也就是说有办法做你想做的事而不会碰到那个bug)。

如果您使用:

order.Product = product;

而不是

product.Orders.Add(order);

它会做你想要的。

问题出在Order对象的FixupProducts方法中(或者更确切地说是与productid setter的交互)。 Fixup方法调用productid setter,setter将Product设置为null,当Fixup方法继续设置productid2时,它会尝试使用该指针异常尝试使用该产品。

当然,在其他情况下你可以遇到类似的问题(虽然我现在想不到任何问题)。如果你看看生成的类,我相信你可以找到一个合适的解决方案。在我的头脑中,我会说在修正中跳过安装人员可以解决问题,但我没有想到其影响或测试过,所以请自行承担风险。

尝试更换:

productid = Product.productid;

productid2 = Product.productid2;

_productid = Product.productid;

_productid2 = Product.productid2;