EF代码 - 首先继承单个基类来实现简单的历史 [英] EF Code-First inherit a single base class to implement easy historocity

查看:281
本文介绍了EF代码 - 首先继承单个基类来实现简单的历史的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如下所述,我遇到了一些执行我的计划的错误。我在解决特定错误方面并不感兴趣,因为我是否是一个好主意。



所有具有历史功能的对象都从一个普通的类 AuditableObject 具有单个属性 public Guid ID {get;组;



后裔可能是:



public class Taco:AuditableObject {public string Seasoning {get;组;现在,我想实现保存事件处理程序写入下表(类)

  public class AuditItem 
{
public Guid ID {get;组; }
public virtual AuditableObject Object {get;组; }
public string ObjectClassName {get;组; } // ugly
public string OldObjectXMLData {get;组; }
public string NewObjectXMLData {get;组; }
public DateTime Timestamp {get;组;
}

我不知道我是否需要 ObjectClassName ,因为我可以在运行时检查对象的类型,但它只是为了防止这种情况。



保存时,我将基本上序列化对象,之后到各自的属性,保存时间戳,并设置对象 - 即映射FK。



这是一个丑陋的方式吗?在我正在做的这个EF Code First中,从单一类下降有明显的缺点吗?

解决方案

我想你会需要当脱盐时,对象的类型的全资格名称,这将是强制性的。



或者序列化对象将导致您的问题。
假设我们将使用该协议审核Taco类的TacoOject1,序列化数据将被置于数据库中,之后由于业务变更,我们需要在T​​aco上添加另一个属性,在重新编译后,当我们需要deserilazed TacoOject1我们将获得 TypeMissMatchException (不知道异常名称)。



另一个设计异议是使用继承来进行审计过程。

第一个:实际上,Taco 不是一个 AuditableObject,它是由Taco使用继承而进行的滚动将违反 Liskov替换原则

第二个:你不能使用多重继承,认为如果我们有一个TacoSupperClass,那么我们如何审核Taco呢?



如果我在设计审核过程中,我将使用实体属性值模型
使 AuditItem 一个标记界面,并将其重命名为 IAuditableEntity

有一个名为的属性审核属性将增强我们的流程。

任何需要审核的实体将被标记为IAuditableEntity,在审计中需要参与的实体的任何财产都将被AuditableProperty属性标记。

  public class Taco:IAuditableEntity 
{
[AuditableProperty]
public string调味{get;组;

[AuditableProperty]
public string OtherProperty1 {get;组; }

public string OtherProperty2 {get;组; }

}

AuditLog 表将有这些列:

1. EntityFullTypeName :( String)我们将审核不同的实体,该字段将被使用(强制性的)

2. ObjectIdentifier :被操纵的实体标识符,实体的主键或业务键。 >
3. FieldName :(String)实体字段名称。

4. OldValue :(String)实体字段旧值。

5. NewValue :(String)实体字段新值。

6. TransactionUser :进行更改的应用程序用户。 (强制性)

7. TransactionID :任何更改实体的操作都需要具有唯一的事务ID(如GUID)(强制性)),如果更改多个字段的实体的更新,这些列将是跟踪更新(转义)中的所有更改的关键点

8. ChangeDate : 交易日期。 (强制性)

9. FieldType :枚举或文本显示字体类型,如TEXT或Double。 (强制性)



在服务层,当Taco1要更新(或插入)时,我们将检查是否使用反射(使用懒惰的chash to存储反射数据),如果有的话,属性已被更改(我们需要单独的数据库调用来获取旧值)。

例如:

  Taco1 = new Taco(); 
Taco1.Seasoning =旧调味价值;
Taco1.OtherProperty1 =Old Other Property1 value;
Taco1.OtherProperty2 =Old Other Property2 value;

保存之前,现在更新:

  Taco1.Seasoning =新调味值; 
Taco1.OtherProperty1 =New Other Property1 value;
Taco1.OtherProperty2 =New Other Property2 value;

我们将在AuditLog中使用相同的TransactionID插入两条记录:





使用此方法
可以跟踪任何实体(表)
报告将被读取
只会更改记录。


I am running into some errors implementing my plan as described below. I am not so interested at this point in resolving particular errors as I am in whether or not this is a good idea.

All history-capable objects descend from a common class AuditableObject with a single property public Guid ID { get; set; }.

A descendent might be:

public class Taco : AuditableObject { public string Seasoning { get; set; } }

Now, I would like to implement the save event handler to write to the following table (class)

public class AuditItem
{
    public Guid ID { get; set; }
    public virtual AuditableObject Object { get; set; }
    public string ObjectClassName { get; set; } //ugly
    public string OldObjectXMLData { get; set; }
    public string NewObjectXMLData { get; set; }
    public DateTime Timestamp { get; set; }
}

I am not sure if I need the ObjectClassName as I can check the type of the object at runtime but it's there just in case.

On save I would basically serialize the object before and after to the respective properties, save a timestamp, and set the object - ie map the FK.

Is this an ugly way to go about it? Are there any obvious drawbacks to descending from a single class with EF Code First as I am doing?

解决方案

I think you will need the full-qualified-name of the object's type when desalinizing, so that will be mandatory.

Alternatively serializing the object will be cause you problems.
Assume that we are going to audit TacoOject1 of Taco class using the approch, the serialized data will be put in data base, later due to business changes we need to add another property to Taco, after recompilation when we need to deserilazed TacoOject1 we will get TypeMissMatchException (not sure of exception name).

Another design objection is using inheritance for audit process.
First: In reality Taco is not a AuditableObject , Its a roll played by Taco, using inheritance will violate Liskov Substitution Principle.
Second: You can not use multiple inheritance, think that if we had a TacoSupperClass, how we could audit Taco then?

If I where going to design auditing process, I would use Entity–attribute–value model
Making AuditItem a marker interface and rename it to IAuditableEntity.
Having an attribute called AuditableProperty would enhance our process.
Any entity needs to be audited will be marked by IAuditableEntity, any property of the entity needed to be partcipated in audit will be marked by AuditableProperty attribute.

public class Taco : IAuditableEntity 
{ 
  [AuditableProperty]
  public string Seasoning { get; set; } 

  [AuditableProperty]
  public string OtherProperty1 { get; set; } 

  public string OtherProperty2 { get; set; } 

}

The AuditLog table will have these columns:
1. EntityFullTypeName: (String) We are going to audit different entities, the field will be used to get meaningful reports .(mandatory)
2. ObjectIdentifier: Entity identifier that is being manipulated, primary key or business key of the entity.
3. FieldName: (String) Entity field name.
4. OldValue: (String) Entity field old value.
5. NewValue: (String) Entity field new value.
6. TransactionUser: Application user that makes the change. (mandatory)
7. TransactionID: Any operation changing the entities will need to have a unique transaction ID (like GUID) (mandatory), In case of an update on an entity changing multiple fields,these column will be the key point to trace all changes in the update(transcation)
8. ChangeDate: Transaction date. (mandatory)
9. FieldType: enumeration or text showing the field type like TEXT or Double. (mandatory)

In service layer when Taco1 is going to be updated(or inserted) we will check if Taco1 type is marked by IAuditableEntity using reflection(using a lazy chash to store reflection data), if so which properties have been changed(we need a separate DB call to fetch old values).
e.g :

Taco1 = new Taco(); 
Taco1.Seasoning = "old Seasoning value";
Taco1.OtherProperty1 = "Old Other Property1 value";
Taco1.OtherProperty2 = "Old Other Property2 value";

Saved before,now updating:

Taco1.Seasoning = "New Seasoning value";
Taco1.OtherProperty1 = "New Other Property1 value";
Taco1.OtherProperty2 = "New Other Property2 value";

We will insert two records in AuditLog with the same TransactionID:

Having this approach
Any entity (table) could be traced
Reports will be readable
Only changes will be logged.

这篇关于EF代码 - 首先继承单个基类来实现简单的历史的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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