【问题标题】:Entity Framework 4 - How to Insert Records with Joiner Tables C#Entity Framework 4 - 如何使用连接器表插入记录 C#
【发布时间】:2012-04-04 09:41:37
【问题描述】:

我一直在编写一个非常庞大的项目,但遇到了 EF4 和连接器表操作的问题。

假设我们有以下 SQL 表定义:

CREATE TABLE [dbo].[SQLEntity](
    [Id] [bigint] IDENTITY(1,1) NOT NULL,
    [Field1] [nvarchar](128) NOT NULL,
    [Field2] [nvarchar] (256),
    [DateAdded] [datetime] NOT NULL,
    CONSTRAINT [PK_SQLEntity] PRIMARY KEY CLUSTERED ( 
        [Id] ASC 
    ) WITH (
        PAD_INDEX = OFF, 
        STATISTICS_NORECOMPUTE = OFF, 
        IGNORE_DUP_KEY = OFF, 
        ALLOW_ROW_LOCKS = ON, 
        ALLOW_PAGE_LOCKS = ON
    ) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

CREATE TABLE [dbo].[Util_LookupValues](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Description] [nvarchar](64) NOT NULL,
    CONSTRAINT [PK_Util_LookupValues] PRIMARY KEY CLUSTERED (
        [Id] ASC
    )WITH (
        PAD_INDEX = OFF, 
        STATISTICS_NORECOMPUTE  = OFF, 
        IGNORE_DUP_KEY = OFF, 
        ALLOW_ROW_LOCKS = ON, 
        ALLOW_PAGE_LOCKS  = ON
    ) ON [PRIMARY]
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[Xref_EntityValues](
    [SQLEntityId] [bigint] NOT NULL,
    [LookupId] [int] NOT NULL,
    CONSTRAINT [PK_Xref_PositionBenefits] PRIMARY KEY CLUSTERED (
        [SQLEntityId] ASC,
        [LookupId] ASC
    )WITH (
        PAD_INDEX = OFF, 
        STATISTICS_NORECOMPUTE = OFF, 
        IGNORE_DUP_KEY = OFF, 
        ALLOW_ROW_LOCKS = ON, 
        ALLOW_PAGE_LOCKS = ON
    ) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[Xref_EntityValues] WITH CHECK ADD CONSTRAINT [FK_Xref_EntityValues_Entity] FOREIGN KEY([SQLEntityId])
REFERENCES [dbo].[SQLEntity] ([Id])
GO

ALTER TABLE [dbo].[Xref_EntityValues] CHECK CONSTRAINT [FK_Xref_EntityValues_Entity]
GO

ALTER TABLE [dbo].[Xref_EntityValues]  WITH CHECK ADD  CONSTRAINT [FK_Xref_EntityValues_Util_LookupValues] FOREIGN KEY([LookupId])
REFERENCES [dbo].[Util_LookupValues] ([Id])
GO

ALTER TABLE [dbo].[Xref_EntityValues] CHECK CONSTRAINT [FK_Xref_EntityValues_Util_LookupValues]
GO

根据这些表创建域模型后,您最终会得到两个实体: SqlEntity 和 Util_LookupValues。

此时,Util_LookupValues 是一个表,其值仅用于查找! Xref_EntityValues 是一个连接表,它将 Entity 对象与查找值联系在一起,允许我们在两者之间建立一对一的关系,保留查找表的“查找”功能。

Util_LookupValues 内容

Id   Description
---  ------------
1    Person
2    Car

如果没有向域模型添加任何更改(让我们为这个问题的目的将其称为 DataEntities),则将 SQLEntity 与 PK 为 1 和 2 的 Util_LookupValues 对象绑定如下:

IEnumerable<Util_LookupValues> lookupValues = DataEntities.Util_LookupValues.Where( lv => lv.Id == 1 || lv.Id == 2);

SQLEntity entity = new SQLEntity();
entity.Field1 = "some field";
entity.Field2 = "another field";
entity.DateAdded = DateTime.Now;

foreach(Util_LookupValues val in lookupValues)
{
    entity.Util_LookupValues.Add(val);     
}

DataEntities.SQLEntities.Add(entity);
DataEntities.SaveChanges();

问题在于,该代码不仅向 Xref_EntityValues 添加值,还向 Util_LookupValues 添加了 1 和 2 的副本以及新的键! 生成的数据库如下:

SQL Entity:
Id  Field1       Field2         DateAdded
-- -------      ------         ----------
1   some field  another field  04/04/2012

Xref_EntityValues:
SQLEntityId   LookupId
-----------   ---------
1              3
1              4

and Util_LookupValues:
Id   Description
---  ------------
1    Person
2    Car
3    Person
4    Car

如何使 Util_LookupValues 仅具有 2 条原始记录而 Xref_EntityValues 具有正确的外键?

Xref_EntityValues:
SQLEntityId   LookupId
-----------   ---------
1              1
1              2

Util_LookupValues:
Id   Description
---  ------------
1    Person
2    Car

【问题讨论】:

  • 我忘了提到,我对可以对 SQL 进行多少更改有些限制。由于此代码用于 Silverlight 4 项目,因此更改域模型还需要更改所有 WCF RIA 服务和非常大的代码库。

标签: c# entity-framework c#-4.0 entity-framework-4 linq-to-entities


【解决方案1】:

这条线...

IEnumerable<Util_LookupValues> lookupValues = DataEntities.Util_LookupValues
    .Where( lv => lv.Id == 1 || lv.Id == 2);

...还有这条线...

DataEntities.SQLEntities.Add(entity);

...使用DataEntities 上下文的相同 实例?您的代码 sn-p 表明,但也许它是“伪代码”。

如果实例不同,您会得到实体的重复,是的。

所以,你有三个选择:

  • 确保上下文实例相同。
  • 将返回的Util_LookupValues 附加到第二个上下文:

    foreach(Util_LookupValues val in lookupValues)
    {
        DataEntities.Util_LookupValues.Attach(val);
        entity.Util_LookupValues.Add(val);     
    }
    
  • 根本不执行第一个查询。而是创建“存根”实体并附加它们:

        var val = new Util_LookupValues { Id = 1 };
        DataEntities.Util_LookupValues.Attach(val);
        entity.Util_LookupValues.Add(val);     
    
        val = new Util_LookupValues { Id = 2 };
        DataEntities.Util_LookupValues.Attach(val);
        entity.Util_LookupValues.Add(val);     
    

    这是因为 EF 只需要在您将对象附加到上下文以建立新关系时知道主键属性值。

【讨论】:

  • 天啊,谢谢,谢谢,谢谢!我从来没有意识到,因为查找实体是通过 DomainContext (DataEntities) 的不同实例检索到的,所以它们被重新复制了!我想我要做的第一件事就是重新附加它们,然后继续执行其余的代码。我马上试试!
猜你喜欢
  • 1970-01-01
  • 2021-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多