13 .net c# entity-framework inotifypropertychanged
我正在玩Entity Framework 4.3,所以我使用DbContext Generator来创建上下文和实体类.
使用默认的EF 4代码生成器模板,实体类实现INotifyPropertyChanged,还可以在属性设置器中添加Changing和Changed部分方法.
当我使用EF 4.x DbContext生成器时,如下图所示,实体类更轻,并且不包括任何跟踪属性更改的方法.

这是一个例子:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
namespace SomeNamespace
{
public partial class SomeTable
{
public SomeTable()
{
this.Children = new HashSet<Child>();
}
public long parent_id { get; set; }
public long id { get; set; }
public string filename { get; set; }
public byte[] file_blob { get; set; }
public virtual Parent Parent { get; set; }
public virtual ICollection<Child> Children { get; set; }
}
}
Run Code Online (Sandbox Code Playgroud)
我必须错过一个重要的难题,但我的搜索没有结果.所以我的问题是:如何使用EF 4.3生成包含属性更改通知的类型?
编辑
我完全同意@derape的答案; 但我很好奇为什么.tt当EF 4默认代码生成模板已经有钩子时我需要更改文件.我的意思是什么时候绑定到WPF DependencyProperty'?如果没有INotifyPropertyChanged,命令对一堆对象中的一组属性所做的更改将不会反映在UI中.我错过了什么?
And*_*ers 23
我最近偶然发现了这个问题,我编辑了我的Entity.tt来实现以下更改,快速补丁但效果很好..
将以下内容添加到CodeStringGenerator类
public string EntityClassOpening(EntityType entity)
{
return string.Format(
CultureInfo.InvariantCulture,
"{0} {1}partial class {2}{3} : {4}",
Accessibility.ForType(entity),
_code.SpaceAfter(_code.AbstractOption(entity)),
_code.Escape(entity),
_code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType)),
"INotifyPropertyChanged");
}
public string Property(EdmProperty edmProperty)
{
return string.Format(
CultureInfo.InvariantCulture,
"{0} {1} {2} {{ {3}{6} {4}{5} }}",
Accessibility.ForProperty(edmProperty),
_typeMapper.GetTypeName(edmProperty.TypeUsage),
_code.Escape(edmProperty),
_code.SpaceAfter(Accessibility.ForGetter(edmProperty)),
_code.SpaceAfter(Accessibility.ForSetter(edmProperty)),
"set { _"+_code.Escape(edmProperty).ToLower()+" = value; OnPropertyChanged(\""+_code.Escape(edmProperty)+"\");}",
"get { return _"+_code.Escape(edmProperty).ToLower()+"; }");
}
public string Private(EdmProperty edmProperty) {
return string.Format(
CultureInfo.InvariantCulture,
"{0} {1} _{2};",
"private",
_typeMapper.GetTypeName(edmProperty.TypeUsage),
_code.Escape(edmProperty).ToLower());
}
Run Code Online (Sandbox Code Playgroud)
将以下内容添加到生成器中
using System.ComponentModel;
<#=codeStringGenerator.EntityClassOpening(entity)#>
{
<#
var propertiesWithDefaultValues = typeMapper.GetPropertiesWithDefaultValues(entity);
var collectionNavigationProperties = typeMapper.GetCollectionNavigationProperties(entity);
var complexProperties = typeMapper.GetComplexProperties(entity);
#>
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
Run Code Online (Sandbox Code Playgroud)
并进一步下降
foreach (var edmProperty in simpleProperties)
{
#>
<#=codeStringGenerator.Private(edmProperty)#>
<#=codeStringGenerator.Property(edmProperty)#>
<#
}
foreach(var complexProperty in complexProperties)
{
#>
<#=codeStringGenerator.Private(complexProperty)#>
<#=codeStringGenerator.Property(complexProperty)#>
<#
}
Run Code Online (Sandbox Code Playgroud)
Bri*_*hey 14
我创建了Anders答案的变体,但有以下不同之处:
所以我的步骤是:
为要扩展的模型类创建基类:
public abstract class BaseModel : INotifyPropertyChanged
{
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
{
if (object.Equals(storage, value)) return false;
storage = value;
this.OnPropertyChanged(propertyName);
return true;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Run Code Online (Sandbox Code Playgroud)
感谢Juan Pable Gomez建议的改进!我喜欢你的改进,即使其他评论者没有:)
将Entity.tt文件中的EntityClassOpening方法更新为以下内容:
public string EntityClassOpening(EntityType entity)
{
return string.Format(
CultureInfo.InvariantCulture,
"{0} {1}partial class {2}{3}",
Accessibility.ForType(entity),
_code.SpaceAfter(_code.AbstractOption(entity)),
_code.Escape(entity),
_code.StringBefore(" : ", string.IsNullOrEmpty(_typeMapper.GetTypeName(entity.BaseType)) ? "BaseModel" : _typeMapper.GetTypeName(entity.BaseType)));
}
Run Code Online (Sandbox Code Playgroud)
找到这一行:
<#=Accessibility.ForType(complex)#> partial class <#=code.Escape(complex)#>
Run Code Online (Sandbox Code Playgroud)
并将其更新为:
<#=Accessibility.ForType(complex)#> partial class <#=code.Escape(complex)#> : BaseModel
Run Code Online (Sandbox Code Playgroud)
谢谢Manolo!
将Entity.tt文件中的Property方法更新为以下内容:
public string Property(EdmProperty edmProperty)
{
return string.Format(
CultureInfo.InvariantCulture,
"private {1} {3};\r\n"+
"\t{0} {1} {2} \r\n" +
"\t{{ \r\n" +
"\t\t{4}get {{ return {3}; }} \r\n" +
"\t\t{5}set {{ SetProperty(ref {3}, value); }} \r\n" +
"\t}}\r\n",
Accessibility.ForProperty(edmProperty),
_typeMapper.GetTypeName(edmProperty.TypeUsage),
_code.Escape(edmProperty),
"_" + Char.ToLowerInvariant(_code.Escape(edmProperty)[0]) + _code.Escape(edmProperty).Substring(1),
_code.SpaceAfter(Accessibility.ForGetter(edmProperty)),
_code.SpaceAfter(Accessibility.ForSetter(edmProperty)));
}
Run Code Online (Sandbox Code Playgroud)
你完成了!现在你的模型类看起来像:
public partial class User : BaseModel
{
private int _id;
public int Id
{
get { return _id; }
set { SetProperty(ref _id,value);}
}
private string _name;
public string Name
{
get { return _name; }
set { SetProperty(ref _name , value); }
}
Run Code Online (Sandbox Code Playgroud)
如果您能看到其他改进,请随时(尝试)编辑此解决方案.
我试图编辑Brian Hinchey解决方案但是EDIT被拒绝了.然后我在这里发布我的addapts.
此解决方案为每个属性Setter生成较少的代码,利用CallerMemberName属性.
注意:我使用的是EF 6.1,它运行良好.
BaseClass现在看起来像这样.
public abstract class BaseModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
{
if (object.Equals(storage, value)) return false;
storage = value;
this.OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var eventHandler = this.PropertyChanged;
if (eventHandler != null)
{
eventHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Run Code Online (Sandbox Code Playgroud)
更新Entity.tt中的EntityClassOpening方法,完全像Brian的那样:
public string EntityClassOpening(EntityType entity)
{
return string.Format(
CultureInfo.InvariantCulture,
"{0} {1}partial class {2}{3}",
Accessibility.ForType(entity),
_code.SpaceAfter(_code.AbstractOption(entity)),
_code.Escape(entity),
_code.StringBefore(" : ", string.IsNullOrEmpty(_typeMapper.GetTypeName(entity.BaseType)) ? "BaseModel" : _typeMapper.GetTypeName(entity.BaseType)));
}
Run Code Online (Sandbox Code Playgroud)
正如布莱恩所说,记得改变:
<#=Accessibility.ForType(complex)#> partial class <#=code.Escape(complex)#>
FOR
<#=Accessibility.ForType(complex)#> partial class <#=code.Escape(complex)#> : BaseModel
Run Code Online (Sandbox Code Playgroud)
我的最后一个改变是Property方法
public string Property(EdmProperty edmProperty)
{
return string.Format(
CultureInfo.InvariantCulture,
"private {1} {3};\r\n"+
"\t{0} {1} {2} \r\n" +
"\t{{ \r\n" +
"\t\t{4}get {{ return {3}; }} \r\n" +
"\t\t{5}set {{ SetProperty(ref {3}, value); }} \r\n" +
"\t}}\r\n",
Accessibility.ForProperty(edmProperty),
_typeMapper.GetTypeName(edmProperty.TypeUsage),
_code.Escape(edmProperty),
"_" + Char.ToLowerInvariant(_code.Escape(edmProperty)[0]) + _code.Escape(edmProperty).Substring(1),
_code.SpaceAfter(Accessibility.ForGetter(edmProperty)),
_code.SpaceAfter(Accessibility.ForSetter(edmProperty)));
}
Run Code Online (Sandbox Code Playgroud)
最后这个类看起来像:
public partial class User : BaseModel
{
private int _id;
public int Id
{
get { return _id; }
set { SetProperty(ref _id , value);}
}
private string _name;
public string Name
{
get { return _name; }
set { SetProperty(ref _name , value);}
}
}
Run Code Online (Sandbox Code Playgroud)
这使得生成的clases更轻.
最近我在使用PropertyChanged.Fody库,但原因不明(至少对我而言)它有时无法正常工作.这就是我降落在这里的原因.这个解决方案(布莱恩的解决方案)每次都有效.
好吧,这取决于你想做什么。如果您只想实现自定义属性/方法,您可以使用部分类的功能。如果您想更改实体设计器中属性的 setter/getter,则必须调整 dbContext 生成器模板文件。这是一个T4模板。
| 归档时间: |
|
| 查看次数: |
12657 次 |
| 最近记录: |