2013-02-05 67 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

希望有所幫助。