如何在Entity Framework中覆盖对象的保存行为

时间:2013-02-05 19:54:59

标签: c# asp.net-mvc-4 entity-framework-5

我有这样的课程:

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

4 个答案:

答案 0 :(得分:1)

asp.net上的一位作者实际上已经实现了你想要做的事情,几乎是一个发球台。您可能希望关注该项目中的几点以帮助您入门。该项目的链接是here

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

您的解决方案:

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

本教程实际上将使用Course ControllerUnit Of Work ClassRepositories完成实施。在本教程结束时,它将使用automatic properties实现这些DbContext,如下所示:

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

希望有所帮助。

答案 1 :(得分: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 += ...
}

并在将格式发送回数据库之前进行格式化。

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

答案 2 :(得分:0)

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

我将专注于存储库模式,您可以找到很多有关的信息 网上整个数据访问层的设计。

例如,要管理课程,您的应用程序应该依赖于像这样的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网站:

答案 3 :(得分:0)

您应该尽可能简化模型,只保留自动属性和属性。对于更复杂的业务逻辑,最好在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。