加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > MsSql教程 > 正文

linq-to-sql – 实体框架:设置新对象引用时自动更新外键

发布时间:2020-12-12 06:41:59 所属栏目:MsSql教程 来源:网络整理
导读:我正在将现有的应用程序从 Linq移植到SQL到Entity Framework 4(默认代码生成). 我注意到两者之间的一个区别是重置对象引用时不会更新外键属性.现在我需要决定如何处理这个问题. 例如,假设您有两种实体类型,Company和Employee.一家公司有很多员工. 在Linq To S
我正在将现有的应用程序从 Linq移植到SQL到Entity Framework 4(默认代码生成).

我注意到两者之间的一个区别是重置对象引用时不会更新外键属性.现在我需要决定如何处理这个问题.

例如,假设您有两种实体类型,Company和Employee.一家公司有很多员工.

在Linq To SQL中,设置公司还设置公司ID:

var company=new Company(ID=1);
var employee=new Employee();
Debug.Assert(employee.CompanyID==0);
employee.Company=company;
Debug.Assert(employee.CompanyID==1); //Works fine!

在实体框架中(并且不使用任何代码模板自定义),这不起作用:

var company=new Company(ID=1);
var employee=new Employee();
Debug.Assert(employee.CompanyID==0);
employee.Company=company;
Debug.Assert(employee.CompanyID==1); //Throws,since CompanyID was not updated!

如何使EF的行为与LinqToSQL相同?我看了一下默认代码生成T4模板,但我无法弄清楚如何进行必要的更改.看起来像一个单行应该可以做到这一点,但我无法弄清楚如何获取给定引用的ID属性.

解决方法

从我在默认T4模板中看到的内容,实体的外键属性不直接链接到与密钥关联的实体引用.

有一对夫妇可以解决从Linq到SQL迁移到EF4的问题.其中之一是注册您的关联的AssociationChanged事件,以便它自动更新您的字段.在您的上下文中,一种方法可能是这样的:

// Extends Employee entity
public partial class Employee
{
    private void CompanyChanged(Object sender,CollectionChangeEventArgs e)
    {
        // Apply reactive changes; aka set CompanyID
        // here
    }

    // Create a default constructor that registers your event handler
    public Employee()
    {
        this.CompanyReference.AssociationChanged += CompanyChanged;
    }
}

就个人而言,如果您想限制维护此类逻辑所需的维护,我建议您更改T4模板(自行更改或找到一个),以便在公司更改时设置CompanyId,如前所示.

Gil Fink用EF4为T4模板写了一篇相当不错的介绍,你可以查阅Scott Hanselman包含一大堆有用的链接和资源来使用T4模板.

最后一点,除非我弄错了,直接访问外键作为实体的属性是从EF3.5到4的新内容.在3.5中,只有通过关联实体(Employee.Company.CompanyID)才能访问它. ).我相信在EF4中添加了该功能,因此您无需加载关联(使用“include”)以便在从数据存储中进行选择时获取外键.

也许EF对此的看法是,如果你有了关联,那么首先要通过协会来获取ID.但这只是猜测,因为我没有报价支持它.

[编辑2010-06-16]:
在对edmx xml元素进行快速读取和分析之后,我发现了一个名为ReferentialConstraint的内容,它似乎包含指定FK_Relation的外键字段.

下面是在默认的T4 edmx模板内部修改的代码片段,写入导航属性部分. (Template_RegionNavigationProperties),围绕未修改模板的第388行.试着忽略可怕的格式……

<#=code.SpaceAfter(NewModifier(navProperty))#><#=Accessibility.ForProperty(navProperty)#> <#=MultiSchemaEscape(navProperty.ToEndMember.GetEntityType(),code)#> <#=code.Escape(navProperty)#>
    {
        <#=code.SpaceAfter(Accessibility.ForGetter(navProperty))#>get
        {
            return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<<#=MultiSchemaEscape(navProperty.ToEndMember.GetEntityType(),code)#>>("<#=navProperty.RelationshipType.FullName#>","<#=navProperty.ToEndMember.Name#>").Value;
        }
        <#=code.SpaceAfter(Accessibility.ForSetter(navProperty))#>set
        {
            // edit begins here
            if(value != null)
            {
                // Automatically sets the foreign key attributes according to linked entity

<#
            AssociationType association = GetSourceSchemaTypes<AssociationType>().FirstOrDefault(_ => _.FullName == navProperty.RelationshipType.FullName);
            foreach(var cons in  association.ReferentialConstraints)
            {
                foreach(var metadataProperty in cons.FromProperties)
                {
#>
                this.<#=metadataProperty.Name#> = value.<#=metadataProperty.Name#>;
                //this._<#=metadataProperty.Name#> = value._<#=metadataProperty.Name#>; // use private field to bypass the OnChanged events,property validation and the likes..

<#
                }
            }
#>  
            }
            else
            {
                // what usually happens in Linq-to-SQL when an association is set to null
                // here
            }
            // edit ends here

            ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<<#=MultiSchemaEscape(navProperty.ToEndMember.GetEntityType(),"<#=navProperty.ToEndMember.Name#>").Value = value;
        }
    }

我粗略测试了它,但它是一个给定的一些验证和这样的缺失.也许无论如何,它都可以为您提供解决方案.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读