如何覆盖实体框架中对象的保存行为
本文关键字:对象 保存 框架 实体 何覆盖 覆盖 | 更新日期: 2023-09-27 17:57:54
我有一门这样的课程:
public class course
{
public int CourseID { get; set; }
public string Name { get; set; }
public Event Schedule {get; set;} //Event is coming from library Dday.iCal
}
实体框架无法正确理解如何保存此属性。(我想在保存时将其序列化为字符串,并在应用程序中使用它时将其作为事件。)所以我有两个方法,比如SerializeToString()和DeserializeFromString()。我希望这些方法只在保存到数据库时应用。
我想到了以下内容。基本上,我试图将一个单独的属性作为字符串保存在数据库中,Event将被忽略,但它现在没有将任何内容保存到数据库中。我甚至不确定这是一个好的做事方法,还是有更好的方法可以做
public class course
{
public int CourseID { get; set; }
public string Name { get; set; }
private Event _Schedule;
[NotMapped]
public Event Schedule {
get
{
if (!String.IsNullOrEmpty(CourseSchedule))
{
return DeserilizeFromString(CourseSchedule);
}
return new Event();
}
set
{
_schedule = value;
}
}
private string _courseSchedule;
public string CourseSchedule {
get
{
return _courseSchedule;
}
private set
{
if (Schedule != null)
{
_courseSchedule = SerializeToString(Schedule);
}
else
{
_courseSchedule = null;
}
}
}
asp.net上的一位作者实际上已经实现了您想要做的事情,几乎达到了极限。你可能想从该项目中的几点开始。该项目的链接在这里。
需要注意的是,它确实使用了在实体框架中实现的DbContext Api
。上面提到的一些抽象是这样的:
您的解决方案:
- 型号
- 查看
- 控制器
- 数据访问层(DAL)
本教程将实际介绍使用Course Controller
、Unit Of Work Class
和Repositories
的实现。在本教程结束时,它将使用DbContext
实现这些automatic properties
,如下所示:
// Model:
public abstract class Person
{
[Key]
public int PersonID { get; set; }
[Required(ErrorMessage = "Last name is required.")]
[Display(Name = "Last Name")]
[MaxLength(50)]
public string LastName { get; set; }
[Required(ErrorMessage = "First name is required.")]
[Column("FirstName")]
[Display(Name = "First Name")]
[MaxLength(50)]
public string FirstMidName { get; set; }
public string FullName
{
get
{
return LastName + ", " + FirstMidName;
}
}
}
// Repository:
public class StudentRepository : IStudentRepository, IDisposable
{
private SchoolContext context;
public StudentRepository(SchoolContext context)
{
this.context = context;
}
public IEnumerable<Student> GetStudents()
{
return context.Students.ToList();
}
public Student GetStudentByID(int id)
{
return context.Students.Find(id);
}
public void InsertStudent(Student student)
{
context.Students.Add(student);
}
public void DeleteStudent(int studentID)
{
Student student = context.Students.Find(studentID);
context.Students.Remove(student);
}
public void UpdateStudent(Student student)
{
context.Entry(student).State = EntityState.Modified;
}
public void Save()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
// Interface for Repository:
public interface IStudentRepository : IDisposable
{
IEnumerable<Student> GetStudents();
Student GetStudentByID(int studentId);
void InsertStudent(Student student);
void DeleteStudent(int studentID);
void UpdateStudent(Student student);
void Save();
}
// Context to Generate Database:
public class SchoolContext : DbContext
{
public DbSet<Course> Courses { get; set; }
public DbSet<Department> Departments { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Instructor> Instructors { get; set; }
public DbSet<Student> Students { get; set; }
public DbSet<Person> People { get; set; }
public DbSet<OfficeAssignment> OfficeAssignments { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Instructor>()
.HasOptional(p => p.OfficeAssignment).WithRequired(p => p.Instructor);
modelBuilder.Entity<Course>()
.HasMany(c => c.Instructors).WithMany(i => i.Courses)
.Map(t => t.MapLeftKey("CourseID")
.MapRightKey("PersonID")
.ToTable("CourseInstructor"));
modelBuilder.Entity<Department>()
.HasOptional(x => x.Administrator);
}
}
// Unit Of Work
public class UnitOfWork : IDisposable
{
private SchoolContext context = new SchoolContext();
private GenericRepository<Department> departmentRepository;
private CourseRepository courseRepository;
public GenericRepository<Department> DepartmentRepository
{
get
{
if (this.departmentRepository == null)
{
this.departmentRepository = new GenericRepository<Department>(context);
}
return departmentRepository;
}
}
public CourseRepository CourseRepository
{
get
{
if (this.courseRepository == null)
{
this.courseRepository = new CourseRepository(context);
}
return courseRepository;
}
}
public void Save()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
这是本课的一些内容,我相信它会非常明确地回答您的问题,同时让您了解抽象为什么有效,因为它确实实现了Fluent Api
。
希望能有所帮助。
您应该尽可能地保持模型的极简主义,只保留auto属性和属性。对于更复杂的业务逻辑,最好在MVC模式中添加另一层。这个通常被称为Repository(虽然很难找到关于Repository Pattern的好教程..:(),它介于模型和控制器之间。
这对于执行单元测试也非常有用。当正确实现时,它允许您在测试期间用集合替换数据库依赖项。这种方法将需要对项目进行大量额外的工作。
还有一种方法(更简单的方法)是添加ViewModel层。这样做:
class MyModel
{
public string Text { get; set; }
}
class MyViewModel : MyModel
{
public new string Text
{
get { return base.Text; }
set { base.Text =value.ToUpper(); }
}
}
class Program
{
static void Main(string[] args)
{
MyViewModel mvm = new MyViewModel();
mvm.Text = "hello there";
var s = ((MyModel) mvm).Text; // "HELLO THERE"
}
}
在DataContext中使用MyModel,在控制器中使用MyViewModel。
如果你有一个模型看起来像这个
using (LolEntities context = new LolEntities)
{
...
}
在应用程序的某个地方,定义了这个模型,通常是这样的:
public partial class LolEntities : ObjectContext
(1) 请注意,该类是分部类,因此您可以创建另一个具有相同名称的分部类并重写:
public override int SaveChanges(SaveOptions options)
(2) 或者你可以只捕捉事件:
using (DemoAZ_8_0Entities context = new DemoAZ_8_0Entities())
{
context.SavingChanges += ...
}
并在它被发送回数据库之前进行格式化。
在您的模型中,只需确保包含一个正确映射到DB中的列的属性。
也许可以在这个逻辑上引入一些抽象,您可以重新创建工作单元和存储库模式,并以更方便的方式添加所需的逻辑。例如,在Course存储库类中,可以对序列化和反序列化事件字段的add and find方法进行成本计算。
我将重点介绍存储库模式,您可以找到许多关于整个web数据访问层的设计。
例如,为了管理课程,您的应用程序应该依赖于像这样的ICourseRepository接口
interface ICourseRepository
{
void Add(Course newCourse);
Course FindByID(int id);
}
您提供以下实现:
class CourseRepository
{
// DbContext and maybe other fields
public void Add(Course c)
{
// Serialize the event field before save the object
_courses.Add(c); // calling entity framework functions, note
// that '_courses' variable could be an DBSet from EF
}
public Course FindById(int id)
{
var course = /// utilize EF functions here to retrieve the object
// In course variable deserialize the event field before to return it ...
}
}
请注意,EF中的ObjectContext是该模式的实现,如果您将来不想更改ORM,您可以覆盖EF上的Save方法。
如果你想了解更多关于这种模式的信息,你可以访问Martin Fowler网站:
工作单元模式
存储库模式