Entiy Framework研究 - 基础设施层

时间:2022-08-31 18:17:21

基础设施层主要包含3个项目:

一、数据实体,对应到数据的表和视图

     在这里有个基础实体类,用来限定repository的泛型实体传入,也重载了一些方法hashcode之类的,方便做数据实体比较,还有一个辅助生成主键的类,代码如下:

     1. Entity类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Chart.Workflow.Infrastructure.Data
{
public class Entity
{
#region Members

int? _requestedHashCode;
string _Id;

#endregion

#region Properties

/// <summary>
/// Get the persisten object identifier
/// </summary>
public virtual string Id
{
get
{
return _Id;
}
protected set
{
_Id = value;
}
}

#endregion

#region Public Methods

/// <summary>
/// Check if this entity is transient, ie, without identity at this moment
/// </summary>
/// <returns>True if entity is transient, else false</returns>
public bool IsTransient()
{
return string.IsNullOrEmpty(this.Id);
}

/// <summary>
/// Generate identity for this entity
/// </summary>
public void GenerateNewIdentity()
{
if (IsTransient())
this.Id = IdentityGenerator.NewSequentialId();
}

/// <summary>
/// Change current identity for a new non transient identity
/// </summary>
/// <param name="identity">the new identity</param>
public void ChangeCurrentIdentity(string identity)
{
if (!string.IsNullOrEmpty(this.Id))
this.Id = identity;
}

#endregion

#region Overrides Methods

/// <summary>
/// <see cref="M:System.Object.Equals"/>
/// </summary>
/// <param name="obj"><see cref="M:System.Object.Equals"/></param>
/// <returns><see cref="M:System.Object.Equals"/></returns>
public override bool Equals(object obj)
{
if (obj == null || !(obj is Entity))
return false;

if (Object.ReferenceEquals(this, obj))
return true;

Entity item = (Entity)obj;

if (item.IsTransient() || this.IsTransient())
return false;
else
return item.Id == this.Id;
}

/// <summary>
/// <see cref="M:System.Object.GetHashCode"/>
/// </summary>
/// <returns><see cref="M:System.Object.GetHashCode"/></returns>
public override int GetHashCode()
{
if (!IsTransient())
{
if (!_requestedHashCode.HasValue)
_requestedHashCode = this.Id.GetHashCode() ^ 31;
// XOR for random distribution
(http://blogs.msdn.com/b/ericlippert/archive/2011/02/28/guidelines-and-rules-for-gethashcode.aspx)

return _requestedHashCode.Value;
}
else
return base.GetHashCode();

}

public static bool operator ==(Entity left, Entity right)
{
if (Object.Equals(left, null))
return (Object.Equals(right, null)) ? true : false;
else
return left.Equals(right);
}

public static bool operator !=(Entity left, Entity right)
{
return !(left == right);
}

#endregion

}
}

     2. IdentityGenerator类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Chart.Workflow.Infrastructure.Data
{
public static class IdentityGenerator
{
/// <summary>
/// This algorithm generates secuential strings across system boundaries, ideal for databases
/// </summary>
/// <returns></returns>
public static string NewSequentialId()
{
string resut = Guid.NewGuid().ToString().Replace("-", "");
return resut;
}

/// <summary>
/// This algorithm generates secuential strings across system boundaries, ideal for databases
/// </summary>
/// <returns></returns>
public static Guid NewSequentialGuid()
{
byte[] uid = Guid.NewGuid().ToByteArray();
byte[] binDate = BitConverter.GetBytes(DateTime.UtcNow.Ticks);

byte[] secuentialGuid = new byte[uid.Length];

secuentialGuid[0] = uid[0];
secuentialGuid[1] = uid[1];
secuentialGuid[2] = uid[2];
secuentialGuid[3] = uid[3];
secuentialGuid[4] = uid[4];
secuentialGuid[5] = uid[5];
secuentialGuid[6] = uid[6];
// set the first part of the 8th byte to '1100' so
// later we'll be able to validate it was generated by us

secuentialGuid[7] = (byte)(0xc0 | (0xf & uid[7]));

// the last 8 bytes are sequential,
// it minimizes index fragmentation
// to a degree as long as there are not a large
// number of Secuential-Guids generated per millisecond

secuentialGuid[9] = binDate[0];
secuentialGuid[8] = binDate[1];
secuentialGuid[15] = binDate[2];
secuentialGuid[14] = binDate[3];
secuentialGuid[13] = binDate[4];
secuentialGuid[12] = binDate[5];
secuentialGuid[11] = binDate[6];
secuentialGuid[10] = binDate[7];

return new Guid(secuentialGuid);
}
}
}


二、辅助切面,主要用来全局的东西:包含验证,日志,资源之类的;

      基础方法如下:

Entiy Framework研究 - 基础设施层

三、数据上下文,主要是基础的数据访问操作实现

     1. ISql接口,做sql语句查询使用,如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Chart.Workflow.Infrastructure.Context
{
public interface ISql
{
IEnumerable<TEntity> ExecuteQuery<TEntity>(string sqlQuery, params object[] parameters);
int ExecuteCommand(string sqlCommand, params object[] parameters);

}
}

     2. IQueryUnitOfWork类,简单数据的操作,如下:

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Chart.Workflow.Infrastructure.Context
{
public interface IQueryUnitOfWork:IUnitOfWork,ISql
{
DbSet<TEntity> CreateSet<TEntity>() where TEntity : class;

void Attach<TEntity>(TEntity item) where TEntity : class;

void SetModified<TEntity>(TEntity item) where TEntity : class;

void ApplyCurrentValues<TEntity>(TEntity original, TEntity current) where TEntity : class;
}
}

     3. IUnitOfWork接口,数据事务性操作,如下:

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Chart.Workflow.Infrastructure.Context
{
public interface IUnitOfWork : IDisposable
{
void Commit();

void CommitAndRefreshChanges();

void RollbackChanges();
}
}

     4. UnitOfWork类,具体核心实现数据操作,如下:

using Chart.Workflow.Infrastructure.Data;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Chart.Workflow.Infrastructure.Context
{
public class UnitOfWork : DbContext, IQueryUnitOfWork
{
IDbSet<Student> _students;
public IDbSet<Student> Students
{
get
{
if (_students == null)
_students = base.Set<Student>();

return _students;
}
}
IDbSet<Course> _course;
public IDbSet<Course> Courses
{
get
{
if (_course == null)
_course = base.Set<Course>();

return _course;
}
}
public UnitOfWork()
:base()
{

}
public UnitOfWork(string connectionstring)
:base(connectionstring)
{

}

#region IQueryUnitOfWork Members
public DbSet<TEntity> CreateSet<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}

public void Attach<TEntity>(TEntity item) where TEntity : class
{
//attach and set as unchanged
base.Entry<TEntity>(item).State = System.Data.EntityState.Unchanged;
}

public void SetModified<TEntity>(TEntity item) where TEntity : class
{
//this operation also attach item in object state manager
base.Entry<TEntity>(item).State = System.Data.EntityState.Modified;
}

public void ApplyCurrentValues<TEntity>(TEntity original, TEntity current) where TEntity : class
{
//if it is not attached, attach original and set current values
base.Entry<TEntity>(original).CurrentValues.SetValues(current);
}

public void Commit()
{
base.SaveChanges();
}

public void CommitAndRefreshChanges()
{
bool saveFailed = false;

do
{
try
{
base.SaveChanges();

saveFailed = false;

}
catch (DbUpdateConcurrencyException ex)
{
saveFailed = true;

ex.Entries.ToList()
.ForEach(entry =>
{
entry.OriginalValues.SetValues(entry.GetDatabaseValues());
});

}
} while (saveFailed);
}

public void RollbackChanges()
{
// set all entities in change tracker
// as 'unchanged state'
base.ChangeTracker.Entries()
.ToList()
.ForEach(entry => entry.State = System.Data.EntityState.Unchanged);
}

public IEnumerable<TEntity> ExecuteQuery<TEntity>(string sqlQuery, params object[] parameters)
{
if (parameters == null)
{
parameters = new object[0];
}
return base.Database.SqlQuery<TEntity>(sqlQuery, parameters);
}

public int ExecuteCommand(string sqlCommand, params object[] parameters)
{
if (parameters == null)
{
parameters = new object[0];
}
return base.Database.ExecuteSqlCommand(sqlCommand, parameters);
}
#endregion


#region DbContext Overrides
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Remove unused conventions
//OneToManyCascadeDeleteConvention
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
//数据库表和实体类型不一致使用
modelBuilder.Entity<Student>().ToTable("Student");
modelBuilder.Entity<Course>().ToTable("Course");
//数据库字段条件限制配置文件
modelBuilder.Configurations.Add(new StudentEntityTypeConfiguration());
modelBuilder.Configurations.Add(new CourseEntityTypeConfiguration());
}
#endregion
}
}