使用INotifyPropertyChanged与实体框架6 DbContext生成器 [英] Using INotifyPropertyChanged with Entity Framework 6 DbContext Generator

查看:174
本文介绍了使用INotifyPropertyChanged与实体框架6 DbContext生成器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道我可以使用ObjectContext,但我喜欢DbContext / DbSet的功能。我的应用程序不够大,不足以保证我编写复杂的视图模型,所以我想直接在EF生成的模型上实现更改通知。



如何实现这个?

解决方案

这可以通过将默认的T4模板(Entity Framework自动添加的.tt文件)替换为以下,然后右键单击.tt文件并选择运行自定义工具。



重要提示:这将重新生成您的模型,这将导致任何自定义项被丢弃。我建议您通过模板实现自定义,而不是直接修改模型类,以防止以后再次出现问题。



注意:替换 string inputFile = @MessageLog.edmx; 与您的edmx文件的名称。

  <#@ template language =C#debug =falsehostspecific =true#> 
<#@ include file =EF.Utility.CS.ttinclude#><#@
输出扩展名=。cs#><#

CodeGenerationTools code = new CodeGenerationTools(this);
MetadataLoader loader = new MetadataLoader(this);
CodeRegion region = new CodeRegion(this,1);
MetadataTools ef = new MetadataTools(this);

string inputFile = @MessageLog.edmx;
EdmItemCollection ItemCollection = loader.CreateEdmItemCollection(inputFile);
string namespaceName = code.VsNamespaceSuggestion();

EntityFrameworkTemplateFileManager fileManager = EntityFrameworkTemplateFileManager.Create(this);
WriteHeader(fileManager);

foreach(ItemCollection.GetItems< EntityType>()中的var实体)OrderBy(e => e.Name)
{
fileManager.StartNewFile(entity.Name + 的.cs);
BeginNamespace(namespaceName,code);
#>
使用系统;
使用System.Collections.Generic;
使用System.ComponentModel;

<#= Accessibility.ForType(entity)#> <#= code.SpaceAfter(code.AbstractOption(entity))#> partial class<#= code.Escape(entity)#> :INotifyPropertyChanged<#= code.StringBefore(,,code.Escape(entity.BaseType))#>
{
<#
var propertiesWithDefaultValues = entity.Properties.Where(p => p.TypeUsage.EdmType为PrimitiveType& p.DeclaringType == entity&& p.DefaultValue!= null);
var collectionNavigationProperties = entity.NavigationProperties.Where(np => np.DeclaringType == entity&& np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many);
var complexProperties = entity.Properties.Where(p => p.TypeUsage.EdmType是ComplexType&& p.DeclaringType == entity);

if(propertiesWithDefaultValues.Any()|| collectionNavigationProperties.Any()|| complexProperties.Any())
{
#>
public<#= code.Escape(entity)#>()
{
<#
foreach(var edmProperty in propertiesWithDefaultValues)
{
#>
这个。<#= code.Escape(edmProperty)#> =<#= code.CreateLiteral(edmProperty.DefaultValue)#> ;;
<#
}

foreach(var navigationProperty in collectionNavigationProperties)
{
#>
这个。<#= code.Escape(navigationProperty)#> = new ObservableListSource<<#= code.Escape(navigationProperty.ToEndMember.GetEntityType())#>>();
<#
}

foreach(var complexProperty in complexProperties)
{
#>
这个。<#= code.Escape(complexProperty)#> = new<#= code.Escape(complexProperty.TypeUsage)#>();
<#
}
#>
}

<#
}

var primitiveProperties = entity.Properties.Where(p => p.TypeUsage.EdmType是PrimitiveType& ;& p.DeclaringType == entity);
if(primitiveProperties.Any())
{
foreach(var edmProperty in primitiveProperties)
{
WriteProperty(code,edmProperty);
}
}

if(complexProperties.Any())
{
#>

<#
foreach(var complexProperty in complexProperties)
{
WriteProperty(code,complexProperty);
}
}

var navigationProperties = entity.NavigationProperties.Where(np => np.DeclaringType == entity);
if(navigationProperties.Any())
{
#>

<#
foreach(var navigationProperty in navigationProperties)
{
WriteNavigationProperty(code,navigationProperty);
}
}
#>

#region INotifyPropertyChanged成员
public event PropertyChangedEventHandler PropertyChanged;

protected void OnPropertyChanged(string propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));


protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
if(PropertyChanged!= null)
PropertyChanged(this,e);
}
#endregion
}
<#
EndNamespace(namespaceName);
}

foreach(ItemCollection.GetItems< ComplexType>()中的var complex)OrderBy(e => e.Name)
{
fileManager.StartNewFile (complex.Name +.cs);
BeginNamespace(namespaceName,code);
#>
使用系统;

<#= Accessibility.ForType(complex)#>部分类<#= code.Escape(complex)#>
{
<#
var complexProperties = complex.Properties.Where(p => p.TypeUsage.EdmType为ComplexType& p.DeclaringType == complex);
var propertiesWithDefaultValues = complex.Properties.Where(p => p.TypeUsage.EdmType是PrimitiveType&& p.DeclaringType == complex&& p.DefaultValue!= null);

if(propertiesWithDefaultValues.Any()|| complexProperties.Any())
{
#>
public<#= code.Escape(complex)#>()
{
<#
foreach(var edmProperty in propertiesWithDefaultValues)
{
#>
这个。<#= code.Escape(edmProperty)#> =<#= code.CreateLiteral(edmProperty.DefaultValue)#> ;;
<#
}

foreach(var complexProperty in complexProperties)
{
#>
这个。<#= code.Escape(complexProperty)#> = new<#= code.Escape(complexProperty.TypeUsage)#>();
<#
}
#>
}

<#
}

var primitiveProperties = complex.Properties.Where(p => p.TypeUsage.EdmType为PrimitiveType& ;& p.DeclaringType == complex);
if(primitiveProperties.Any())
{
foreach(var edmProperty in primitiveProperties)
{
WriteProperty(code,edmProperty);
}
}

if(complexProperties.Any())
{
#>

<#
foreach(complexProperties中的var edmProperty)
{
WriteProperty(code,edmProperty);
}
}
#>
}
<#
EndNamespace(namespaceName);
}

if(!VerifyTypesAreCaseInsensitiveUnique(ItemCollection))
{
return;
}

fileManager.Process();

#>
<#+
string GetResourceString(string resourceName)
{
if(_resourceManager == null)
{
_resourceManager = new System.Resources。 ResourceManager(System.Data.Entity.Design,typeof(System.Data.Entity.Design.MetadataItemCollectionFactory).Assembly);
}

return _resourceManager.GetString(resourceName,null);
}
System.Resources.ResourceManager _resourceManager;

void WriteHeader(EntityFrameworkTemplateFileManager fileManager)
{
fileManager.StartHeader();
#>
// -------------------------------------------- ----------------------------------
//< auto-generated>
//<#= GetResourceString(Template_GeneratedCodeCommentLine1)#>
//
//<#= GetResourceString(Template_GeneratedCodeCommentLine2)#>
//<#= GetResourceString(Template_GeneratedCodeCommentLine3)#>
//< / auto-generated>
// -------------------------------------------- ----------------------------------

<#+
fileManager.EndBlock();
}

void BeginNamespace(string namespaceName,CodeGenerationTools code)
{
CodeRegion region = new CodeRegion(this);
if(!String.IsNullOrEmpty(namespaceName))
{
#>
命名空间<#= code.EscapeNamespace(namespaceName)#>
{
<#+
PushIndent(CodeRegion.GetIndent(1));
}
}


void EndNamespace(string namespaceName)
{
if(!String.IsNullOrEmpty(namespaceName))
{
PopIndent();
#>
}
<#+
}
}

void WriteProperty(CodeGenerationTools代码,EdmProperty edmProperty)
{
WriteProperty (Accessibility.ForProperty(edmProperty),
code.Escape(edmProperty.TypeUsage),
code.Escape(edmProperty),
code.SpaceAfter(Accessibility.ForGetter(edmProperty)),
code.SpaceAfter(Accessibility.ForSetter(edmProperty)));
}

void WriteNavigationProperty(CodeGenerationTools code,NavigationProperty navigationProperty)
{
var endType = code.Escape(navigationProperty.ToEndMember.GetEntityType());
WriteProperty(PropertyVirtualModifier(Accessibility.ForProperty(navigationProperty)),
navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many?(ObservableListSource<+ endType +>):endType,
code.Escape(navigationProperty),
code.SpaceAfter(Accessibility.ForGetter(navigationProperty)),
code.SpaceAfter(Accessibility.ForSetter(navigationProperty)));
}

void WriteProperty(string accessibility,string type,string name,string getterAccessibility,string setterAccessibility)
{
#>
private<#= type#> _<#=名#取代;
public<#= type#> <#=名#>
{
<#= getterAccessibility#> get {return _<#= name#> ;;
{#= setterAccessibility#> set
{
if(_<#= name#>!= value)
{
_<#=名#> =值;
OnPropertyChanged(<#= name#>);
}
}
}
<#+
}

string PropertyVirtualModifier(字符串可访问性)
{
return accessibility +(accessibility!=private?virtual:);
}

bool VerifyTypesAreCaseInsensitiveUnique(EdmItemCollection itemCollection)
{
var alreadySeen = new Dictionary< string,bool>(StringComparer.OrdinalIgnoreCase);
foreach(itemCollection.GetItems< StructuralType>()中的var类型)
{
if(!(type是EntityType || type为ComplexType))
{
继续;
}

if(alreadySeen.ContainsKey(type.FullName))
{
错误(String.Format(CultureInfo.CurrentCulture,此模板不支持类型不同的情况,类型{0}不支持,type.FullName));
返回false;
}
else
{
alreadySeen.Add(type.FullName,true);
}
}

返回true;
}
#>


I know I can use ObjectContext instead, but I like the features of DbContext / DbSet. My application isn't large enough to warrant me writing complex view models, so I'd like to implement change notification on the EF generated models directly.

How can I achieve this?

解决方案

This can be achieved by replacing the default T4 template (the .tt file automatically added by Entity Framework) with the following, then right clicking the .tt file and selecting "Run Custom Tool".

Important: This will regenerate your models which will cause any customizations to be discarded. I recommend you implement your customizations via the template rather than modifying the model class directly to prevent this from being a problem in the future.

Note: Replace string inputFile = @"MessageLog.edmx"; with the name of your edmx file.

<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ include file="EF.Utility.CS.ttinclude"#><#@
 output extension=".cs"#><#

CodeGenerationTools code = new CodeGenerationTools(this);
MetadataLoader loader = new MetadataLoader(this);
CodeRegion region = new CodeRegion(this, 1);
MetadataTools ef = new MetadataTools(this);

string inputFile = @"MessageLog.edmx";
EdmItemCollection ItemCollection = loader.CreateEdmItemCollection(inputFile);
string namespaceName = code.VsNamespaceSuggestion();

EntityFrameworkTemplateFileManager fileManager = EntityFrameworkTemplateFileManager.Create(this);
WriteHeader(fileManager);

foreach (var entity in ItemCollection.GetItems<EntityType>().OrderBy(e => e.Name))
{
    fileManager.StartNewFile(entity.Name + ".cs");
    BeginNamespace(namespaceName, code);
#>
using System;
using System.Collections.Generic;
using System.ComponentModel;

<#=Accessibility.ForType(entity)#> <#=code.SpaceAfter(code.AbstractOption(entity))#>partial class <#=code.Escape(entity)#> : INotifyPropertyChanged<#=code.StringBefore(", ", code.Escape(entity.BaseType))#>
{
<#
    var propertiesWithDefaultValues = entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity && p.DefaultValue != null);
    var collectionNavigationProperties = entity.NavigationProperties.Where(np => np.DeclaringType == entity && np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many);
    var complexProperties = entity.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == entity);

    if (propertiesWithDefaultValues.Any() || collectionNavigationProperties.Any() || complexProperties.Any())
    {
#>
    public <#=code.Escape(entity)#>()
    {
<#
        foreach (var edmProperty in propertiesWithDefaultValues)
        {
#>
        this.<#=code.Escape(edmProperty)#> = <#=code.CreateLiteral(edmProperty.DefaultValue)#>;
<#
        }

        foreach (var navigationProperty in collectionNavigationProperties)
        {
#>
        this.<#=code.Escape(navigationProperty)#> = new ObservableListSource<<#=code.Escape(navigationProperty.ToEndMember.GetEntityType())#>>();
<#
        }

        foreach (var complexProperty in complexProperties)
        {
#>
        this.<#=code.Escape(complexProperty)#> = new <#=code.Escape(complexProperty.TypeUsage)#>();
<#
        }
#>
    }

<#
    }

    var primitiveProperties = entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity);
    if (primitiveProperties.Any())
    {
        foreach (var edmProperty in primitiveProperties)
        {
            WriteProperty(code, edmProperty);
        }
    }

    if (complexProperties.Any())
    {
#>

<#
        foreach(var complexProperty in complexProperties)
        {
            WriteProperty(code, complexProperty);
        }
    }

    var navigationProperties = entity.NavigationProperties.Where(np => np.DeclaringType == entity);
    if (navigationProperties.Any())
    {
#>

<#
        foreach (var navigationProperty in navigationProperties)
        {
            WriteNavigationProperty(code, navigationProperty);
        }
    }
#>

    #region INotifyPropertyChanged Members
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
    }

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, e);
    }
    #endregion
}
<#
    EndNamespace(namespaceName);
}

foreach (var complex in ItemCollection.GetItems<ComplexType>().OrderBy(e => e.Name))
{
    fileManager.StartNewFile(complex.Name + ".cs");
    BeginNamespace(namespaceName, code);
#>
using System;

<#=Accessibility.ForType(complex)#> partial class <#=code.Escape(complex)#>
{
<#
    var complexProperties = complex.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == complex);
    var propertiesWithDefaultValues = complex.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == complex && p.DefaultValue != null);

    if (propertiesWithDefaultValues.Any() || complexProperties.Any())
    {
#>
    public <#=code.Escape(complex)#>()
    {
<#
        foreach (var edmProperty in propertiesWithDefaultValues)
        {
#>
        this.<#=code.Escape(edmProperty)#> = <#=code.CreateLiteral(edmProperty.DefaultValue)#>;
<#
        }

        foreach (var complexProperty in complexProperties)
        {
#>
        this.<#=code.Escape(complexProperty)#> = new <#=code.Escape(complexProperty.TypeUsage)#>();
<#
        }
#>
    }

<#
    }

    var primitiveProperties = complex.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == complex);
    if (primitiveProperties.Any())
    {
        foreach(var edmProperty in primitiveProperties)
        {
            WriteProperty(code, edmProperty);
        }
    }

    if (complexProperties.Any())
    {
#>

<#
        foreach(var edmProperty in complexProperties)
        {
            WriteProperty(code, edmProperty);
        }
    }
#>
}
<#
    EndNamespace(namespaceName);
}

if (!VerifyTypesAreCaseInsensitiveUnique(ItemCollection))
{
    return "";
}

fileManager.Process();

#>
<#+
string GetResourceString(string resourceName)
{
    if(_resourceManager == null)
    {
        _resourceManager = new System.Resources.ResourceManager("System.Data.Entity.Design", typeof(System.Data.Entity.Design.MetadataItemCollectionFactory).Assembly);
    }

    return _resourceManager.GetString(resourceName, null);
}
System.Resources.ResourceManager _resourceManager;

void WriteHeader(EntityFrameworkTemplateFileManager fileManager)
{
    fileManager.StartHeader();
#>
//------------------------------------------------------------------------------
// <auto-generated>
// <#=GetResourceString("Template_GeneratedCodeCommentLine1")#>
//
// <#=GetResourceString("Template_GeneratedCodeCommentLine2")#>
// <#=GetResourceString("Template_GeneratedCodeCommentLine3")#>
// </auto-generated>
//------------------------------------------------------------------------------

<#+
    fileManager.EndBlock();
}

void BeginNamespace(string namespaceName, CodeGenerationTools code)
{
    CodeRegion region = new CodeRegion(this);
    if (!String.IsNullOrEmpty(namespaceName))
    {
#>
namespace <#=code.EscapeNamespace(namespaceName)#>
{
<#+
        PushIndent(CodeRegion.GetIndent(1));
    }
}


void EndNamespace(string namespaceName)
{
    if (!String.IsNullOrEmpty(namespaceName))
    {
        PopIndent();
#>
}
<#+
    }
}

void WriteProperty(CodeGenerationTools code, EdmProperty edmProperty)
{
    WriteProperty(Accessibility.ForProperty(edmProperty),
                  code.Escape(edmProperty.TypeUsage),
                  code.Escape(edmProperty),
                  code.SpaceAfter(Accessibility.ForGetter(edmProperty)),
                  code.SpaceAfter(Accessibility.ForSetter(edmProperty)));
}

void WriteNavigationProperty(CodeGenerationTools code, NavigationProperty navigationProperty)
{
    var endType = code.Escape(navigationProperty.ToEndMember.GetEntityType());
    WriteProperty(PropertyVirtualModifier(Accessibility.ForProperty(navigationProperty)),
                  navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ObservableListSource<" + endType + ">") : endType,
                  code.Escape(navigationProperty),
                  code.SpaceAfter(Accessibility.ForGetter(navigationProperty)),
                  code.SpaceAfter(Accessibility.ForSetter(navigationProperty)));
}

void WriteProperty(string accessibility, string type, string name, string getterAccessibility, string setterAccessibility)
{
#>
    private <#=type#> _<#=name#>;
    public <#=type#> <#=name#>
    {
        <#=getterAccessibility#>get { return _<#=name#>; }
        <#=setterAccessibility#>set
        {
            if (_<#=name#> != value)
            {
                _<#=name#> = value;
                OnPropertyChanged("<#=name#>");
            }
        }
    }
<#+
}

string PropertyVirtualModifier(string accessibility)
{
    return accessibility + (accessibility != "private" ? " virtual" : "");
}

bool VerifyTypesAreCaseInsensitiveUnique(EdmItemCollection itemCollection)
{
    var alreadySeen = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
    foreach(var type in itemCollection.GetItems<StructuralType>())
    {
        if (!(type is EntityType || type is ComplexType))
        {
            continue;
        }

        if (alreadySeen.ContainsKey(type.FullName))
        {
            Error(String.Format(CultureInfo.CurrentCulture, "This template does not support types that differ only by case, the types {0} are not supported", type.FullName));
            return false;
        }
        else
        {
            alreadySeen.Add(type.FullName, true);
        }
    }

    return true;
}
#>

这篇关于使用INotifyPropertyChanged与实体框架6 DbContext生成器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆