2013-02-05 71 views
2

我有一个类当然是这样的:如何覆盖保存对象的行为在实体框架

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()。我希望只有在保存到数据库时才应用这些方法。

我想出了以下内容。基本上我试图有一个单独的属性作为一个字符串,将被保存在数据库中,事件将被忽略,但它现在不保存任何东西到数据库。我甚至不知道这是做事情一个很好的办法,或者有更好的东西可以做:

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; 
       } 
      } 
} 
+2

实体框架无法读取您的getter和setter(它假定自动属性)。尝试将该逻辑移至构造函数。 –

+0

@四十二,这是很好的知道。但构造函数只会在创建对象时运行,而不是在操作时运行,对吗?所以它不适合我。如果我想修改对象中的东西,我应该每次重新创建它吗?我在想也许FluentAPI可以在这里帮助,但不知道在哪里应用 – user194076

+0

也许在这个逻辑中引入了一些抽象,可以重新创建工作单元和存储库模式,并以更方便的方式添加所需的逻辑。例如,在课程存储库类中,您可以成本化添加和查找方法序列化和反序列化事件字段。 –

回答

0

你应该让你的模型作为尽可能简约,只是自动属性和属性。对于更复杂的业务逻辑,向MVC模式添加另一个层是很好的。这个通常叫做Repository(很难找到一个关于Repository Pattern的好教程,虽然.. :()并且在模型和控制器控制器之间。

这对于执行单元测试非常有用。做替换在测试与收集数据库依赖这种方法需要对项目一堆额外的工作

还有一个方法(简单的一个)将添加一个视图模型层做这种方式:。

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。

+0

我试图用派生类来实现你的方法,但问题是一旦我创建派生类EF想要添加列表“Discriminator”在表中课程 – user194076

+0

看起来像EF坚持意识到儿童课程。我想变得聪明,并节省您创建传统ViewModel的麻烦(一个单独的类,您的模型作为一个字段,它是自己的属性来访问模型的属性)。这个判别器应该让EF知道你的对象实际属于哪个类。如果您不介意让EF创建此列。否则,创建一个传统的ViewModel。如果您需要更多帮助,请告诉我。 – gisek

0

如果你有一个模型,看起来像这样

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。

在您的模型中,确保包含一个正确映射到数据库中的列的属性。

0

也许在这个逻辑中引入了一些抽象概念,您可以重新创建工作单元和存储库模式,并以更方便的方式添加所需的逻辑。例如,在课程存储库类中,您可以成本化添加和查找方法序列化和反序列化事件字段。

我将关注存储库模式,您可以在网络上找到关于整个数据访问层设计的大量信息 。

例如,管理课程,你的应用程序应该取决于这样

interface ICourseRepository 
{ 
    void Add(Course newCourse); 
    Course FindByID(int id); 
} 

一个ICourseRepository界面上你提供如下因素实现:

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 ... 
    } 
} 

注意,ObjectContext的在EF是这种模式的实现,如果你在将来改变ORM时不感兴趣,你可以重写EF上的Save方法。

如果您想了解更多关于这种模式,您可以访问Martin Fowler的网站:

1

一个在asp.net上的作者实际上已经实现了你想要做什么,几乎到了一个tee。您可能需要遵循该项目中的几个要点来帮助您开始。该项目的链接是here

有些事情需要注意,它确实利用在实体框架中实现的DbContext Api。上面提到的一些抽象的是这样的:

您的解决方案:

  • 型号
  • 查看
  • 控制器
  • 数据访问层(DAL)

本教程将实际上通过执行Course ControllerUnit Of Work ClassRepositories。在本教程的最后将落实这些automatic propertiesDbContext,看起来像这样:

// 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

希望有所帮助。