C# 如何在实体框架中重写对象的保存行为

C# 如何在实体框架中重写对象的保存行为,c#,asp.net-mvc-4,entity-framework-5,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 } 实体框架无法正确理解如何保存此属性。(我想在保存时将其序列化为字符串,

我有一门课是这样的:

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

如果你有一个这样的模型

using (LolEntities context = new LolEntities)
{
...
}
interface ICourseRepository
{
    void Add(Course newCourse);
    Course FindByID(int id);
}
在应用程序中的某个地方,定义了此模型,通常如下所示:

public partial class LolEntities : ObjectContext
// 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;
            }
        }
    }
(1) 请注意,该类是分部类,因此您可以创建另一个具有相同名称的分部类并重写:

public override int SaveChanges(SaveOptions options)
(2) 或者您可以只捕获事件:

using (DemoAZ_8_0Entities context = new DemoAZ_8_0Entities())
{
    context.SavingChanges += ...
}
并在将其发送回数据库之前进行格式化


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

可能会在该逻辑上引入一些抽象,您可以重新创建工作单元和存储库模式,并以更方便的方式添加所需的逻辑。例如,在课程存储库类中,您可以对事件字段序列化和反序列化的add and find方法进行成本分析

我将重点讨论存储库模式,您可以找到关于 整个web数据访问层的设计

例如,要管理课程,您的应用程序应该依赖于这样的ICourseRepository接口

using (LolEntities context = new LolEntities)
{
...
}
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网站:


您应该尽可能地简化模型,只保留自动属性和属性。对于更复杂的业务逻辑,最好在MVC模式中添加另一层。这一个通常被称为Repository(虽然很难找到关于Repository模式的好教程:(),它介于模型和控制器之间

这对于执行单元测试也是非常有用的。当正确实现时,它允许您在测试期间用集合替换数据库依赖关系。这种方法需要在项目上进行大量额外的工作

另一种方法(更简单的方法)是添加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中,在controller中使用MyModel使用MyViewModel。

asp.net上的一位作者实际上已经实现了您的尝试,几乎达到了一个目标。您可能需要遵循该项目中的几点来开始。指向该项目的链接是

需要注意的是,它确实利用了在实体框架中实现的
DbContext Api

public partial class LolEntities : ObjectContext
// 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;
            }
        }
    }
您的解决方案:

  • 模型
  • 看法
  • 控制器
  • 数据访问层(DAL)
本教程将实际使用
课程控制器
工作类单元
存储库
进行实现。在本教程结束时,将使用
DbContext
实现这些
自动属性
,如下所示:

public partial class LolEntities : ObjectContext
// 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;
            }
        }
    }

//存储库:
公共班级学生位置:是否学生位置,可识别
{
私立学校语境;
公共学生定位(学校背景)
{
this.context=上下文;
}
公共IEnumerable GetStudents()
{
返回context.Students.ToList();
}
公立学生GetStudentByID(int id)
{
返回context.Students.Find(id);
}
公共无效插入学生(学生)
{
context.student.Add(学生);
}
公共学生(国际学生ID)
{
Student=context.Students.Find(studentID);
context.student.Remove(学生);
}
公共无效更新学生(学生)
{
context.Entry(student.State=EntityState.Modified;
}
公共作废保存()
{
SaveChanges();
}
私有布尔=假;
受保护的虚拟void Dispose(bool disposing)
{
如果(!this.disposed)
{
如果(处置)
{
context.Dispose();
}
}
这是真的;
}
公共空间处置()
{
处置(真实);
总干事(本);
}
}

//存储库的接口:
公共界面为udentrepository:IDisposable
{
IEnumerable GetStudents();
学生GetStudentByID(int studentId);
无效插入学生(学生);
无效删除学生(国际学生ID);
无效更新学生(学生);
作废保存();
}

//要生成数据库的上下文:
公共课堂背景:DbContext
{
公共数据库集课程{get;set;}
公共数据库集部门{get;set;}
公共数据库集注册{get;set;}
公共DbSet指令器{get;set;}
公共数据库集学生{get;set;}
公共数据库集人物{get;set;}
公共数据库集OfficeSignements{get;set;}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
模式