【问题标题】:EF Core - Repository, Model or View ModelEF Core - 存储库、模型或视图模型
【发布时间】:2022-02-18 06:44:20
【问题描述】:

首先,这是我的课程:

public class Name
{
    public int NameId {get;set;}
    public string Value {get;set;}
    [ForeignKey("Name_NameId")]
    public ICollection<PersonName> PersonsName {get;set;}
}

public class NameType
{
    public int NameTypeId {get;set;}
    public string Value {get;set;}
    [ForeignKey("NameType_NameTypeId")]
    public ICollection<PersonName> PersonsName {get;set;}
}

public class Person
{
    public int PersonId {get;set;}
    public string Suffix {get;set;}
    public datetime DateOfBirth {get;set;}
    [ForeignKey("Person_PersonId")]
    public ICollection<PersonName> PersonsName {get;set;}
}

public class PersonName
{
    public int Person_PersonId {get;set;}
    public int Name_NameId {get;set;}
    public int NameType_NameTypeId {get;set;}
    public int Order {get;set;}
}

理想情况下,在访问 Person 类时,我希望能够调用一个函数(或属性),该函数(或属性)可以从 PersonName 存储库中提取该人的全名。但是,我不太确定该怎么做。这些表中的数据示例:

NameId               Value
1                    John
2                    Jacob
3                    Jingleheimer
4                    Schmidt

NameTypeId           Value
1                    First Name
2                    Middle Name
3                    Last Name
4                    Nickname

PersonId             Suffix                 DateOfBirth
1                                           01/01/1900

Person_PersonId      Name_NameId            NameType_NameTypeId        Order
1                    1                      1                          0
1                    2                      2                          0
1                    3                      2                          1
1                    4                      3                          0

所以在 Person 类中,我希望有一个像 GetFullName()/FullName 这样的函数/属性,它将返回“John Jacomb Jingleheimer Schmidt”。我一直在从头开始学习一个教程,在制作完每个类之后,他们制作了一个接口、模拟存储库,并且正在开发一个数据库存储库。但是,我想通过视图模型将信息传递到视图中,但我不确定如何将类绑定到存储库等。有没有人可以指点我一个可以解释的教程最好还是为我拼出来?谢谢。

【问题讨论】:

  • 你提到你正在学习一个教程——你能把我们链接到它吗?
  • @chakeda - 它在这里:app.pluralsight.com/library/courses/… 在那个教程中,他们没有做我上面想要完成的事情。当我完全按照该教程进行操作时,一切正常。我把它作为我想做的一些个人事情的开始。
  • 这里是40 pitfalls about names。您的人应该只有一个可以为空的名称字段。也就是说,您正在采取数据库规范化的方式。如果您真的想走这条路,您的问题可能是PersonName 中缺少导航属性。然后,您可以从Person 通过PersonName 通过MissingNameNavigationProperty 转到Value 属性。
  • 这种数据库设计很糟糕,除非您从事“名称”业务,这很常见。该名称不应有自己的表。

标签: asp.net-mvc asp.net-core ef-core-2.0


【解决方案1】:

在我看来,您的表格太复杂了。缺点是您必须加入这么多表才能获得某人的全名......并且由于所有连接,您可能会面临性能问题......其他开发人员很难理解和维护此代码。

所以,我知道我没有直接回答您的问题,但我建议您简化表格设计。

为什么不使用一个简单的表格,例如:

public class Person
{
    public int PersonId { get; set; }
    public string FirstName { get; set;}
    public string MiddleName { get; set;}
    public string LastName { get; set; }
    public string NickName { get; set; }
    public string Suffix { get; set; }
    public datetime DateOfBirth { get; set; }

    // it is a lot easier to implement GetFullName() method here than joining so many tables
    public string GetFullName()
    {
        retun FirstName + " " + MidleName + " " + LastName;
    }
}

我真的很难理解你的最后一张桌子:PersonName

public class PersonName
{
    public int Person_PersonId { get; set; }
    public int Name_NameId { get; set; }
    public int NameType_NameTypeId { get; set; }
    public int Order { get; set; } // <-- Why putting Order in PersonName?
}

对我来说,Order 不是 PersonName 表中的逻辑列...我不完全理解您的设计,我可能完全错了...但对我来说,感觉就像一个过度设计的设计。

【讨论】:

  • 该数据库的最终目标之一是让用户能够尽可能“细化”地搜索人员。 Order 列用于可能有多个名字、中间名或姓氏的人。因此,如果某人的名字是“Bob Henry Jackson Jones”,他们将有两个中间名。我将有该人的两条中间名记录,一条用于亨利,一条用于杰克逊,顺序分别为 0 和 1。这样,我可以在显示全名时正确排序,还可以搜索 Henry 作为中间名。它可能过于复杂......
  • 您想创建这么多表只是为了能够单独搜索名称?我觉得你可能会因为搜索而牺牲你的设计。您可以使用我建议的简单表格......然后您可以做很多事情来搜索:您可以编写一个过程来搜索所有名称列,或者您可以在表格顶部编写一个视图,该视图将返回个人名字...如果您有更高级的搜索要求,那么您可以使用众多免费搜索引擎之一,例如Elasticsearch...
【解决方案2】:

希望我能正确理解您的问题

我做了一些假设

我用你的类构建了一个数据库并查询了数据库,所以其他表是通过关系链接的

假设您正在传递人员的 id,并且还假设 dbcontext 可用并在类内部实例化,然后调用 GetFullName

public string GetPersonById(int personId)
{
    var person = db_context.PersonNames.FirstOrDefault(m => m.Person_PersonId == personId);
    //did not check for null here
    var name = person.Person.PersonNames.ToList();
    var fullname = "";
    name.ForEach(m => fulname += m.Name.Value + " ");
    return fullname;
}

public virtual string GetFullName
{
    get { return GetPersonById(PersonId); }// the person id passed, the class if instantiated can call this instance PersonId
    set { ; }
}

您还可以将数据从数据库中获取到您拥有的模型中,并且该方法可以正常工作。从数据库中传递它们可以为您提供关系能力,Razor Engine 在视图中可能会有很大帮助,但是

要获取数据,您需要一个接一个地提取数据并存储在一个列表中。

public void UseModel()
{
    var people = _context.People.ToList();
    var names = _context.Names.ToList();
    var name_types = _context.NameTypes.ToList();

    List<PersonModel> ps = new List<PersonModel>();

    people.ForEach(m =>
    {
        ps.Add(new PersonModel
        {
            PersonId = m.PersonId,
            Suffix = m.Suffix,
            DateOfBirth = m.DateOfBirth,
            PersonsName = null//I suggest you use mapping here see https://stackoverflow.com/questions/16118085/best-practices-for-mapping-one-object-to-another
            //use mapping to map the list or use a fooloop to construct it before this declaration and assign it here
        });
    });
    //do for names and name_types

}

您也可以将此数据作为对象PersonName 传递给View,该对象具有所有

【讨论】:

    【解决方案3】:

    映射您的视图模型。你可以这样使用。

    public class PersonDTO
    {
        public int PersonId { get; set; }
        public string FirstName { get; set;}
        public string MiddleName { get; set;}
        public string LastName { get; set; }
        public string NickName { get; set; }
        public string Suffix { get; set; }
        public datetime DateOfBirth { get; set; }
    
        public string GetFullName()
        {
            retun FirstName + " " + MidleName + " " + LastName;
        }
    }
    

    映射 FirstName 、 MiddleName 、 LastName 、 NickName 。 你可以使用。

    public void MapToPersonDTO(){
    
        var selectedPerson = _context.Person.FirstOrDefault(m => m.PersonId == 1);
    
        var personDto = new PersonDTO(){
            FirstName = _context.Name.FirstOrDefault(n=>n.NameId == selectedPerson.PersonsName.FirstOrDefault(f=>f.NameType_NameTypeId == 1)).Value,
            MiddleName= _context.Name.FirstOrDefault(n=>n.NameId == selectedPerson.PersonsName.FirstOrDefault(f=>f.NameType_NameTypeId == 2)).Value,
            LastName  = _context.Name.FirstOrDefault(n=>n.NameId == selectedPerson.PersonsName.FirstOrDefault(f=>f.NameType_NameTypeId == 3)).Value,
            NickName  = _context.Name.FirstOrDefault(n=>n.NameId == selectedPerson.PersonsName.FirstOrDefault(f=>f.NameType_NameTypeId == 4)).Value,
        };
    }
    

    【讨论】:

      【解决方案4】:

      我也在做这个。我的灵感来自有线电视上的“The First 48”节目,其中“警察”将在他们的数据库中有一个名字,在他们有一个人与事件联系之前很久就编译一个关于个人的文件。或者肖恩·科里·卡特(Shawn Corey Carter)取名为 J-Zee。或者这个,罗杰斯·纳尔逊王子怎么样,他的表演生涯被称为王子,然后他改名为 Logo。为那个添加一列。每当我看到不为复杂而努力的建议时,就让它变得简单。我一直在想,这将如何代表那些场景?

      但鉴于 EF 和 EF Core 的功能,我看到这样的“PersonName”实现。

      public abstract class PeopleName
      {
          public PeopleName()
          {
          }
      
          [Key]
          [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
          public long Id { get; set; }
          [ForeignKey("Person"), Required, Column(Order = 1)]
          public long PersonId { get; set; }
          [ForeignKey("Name"), Required, Column(Order = 2)]
          public long NameId { get; set; }
          public EnumNameType NameType { get; set; }
          public byte NameOrder { get; set; }
      
          public virtual Person? Person { get; set; } = new Person();
          public virtual Name? Name { get; set; } = new Name();
      
      }
      
      
      
      public class FirstName : PeopleName
      {
          [Required]
          public new EnumNameType NameType { get; set; } = 
              EnumNameType.FirstName;
      }
      
      public class LastName : PeopleName
      {
      }
      
      public class FullName : PeopleName
      {
      }
      
      public class Alias : PeopleName
      {
      }
      
      public class MiddleName : PeopleName
      {
      }
      
      public class MiddleInitial : PeopleName
      {
      }
      

      我希望 DTO 可以沿着这条路线完成。我希望有人会告诉我们如何加载一次并在属性之间描述值。

      public class PersonDTO
      {
          public int PersonId { get; set; }
          public string? FirstName
          {
              get
              {
                  var names = NamesLink.OfType<FirstName>().ToList();
                  if (names.Any())
                  {
                      foreach (FirstName? fn in names)
                      {
                          firstName = fn.Name.NameString;
                      }
                  }
                  return firstName;
              }
              set
              {
                  if (value != null)
                  {
                      var name = new Name { NameString = value };
                      var pn = new FirstName { Name = name };
                      NamesLink.Add(pn);
                      firstName = value;
                  }
      
              }
          }
          private string? firstName;
          public string? LastName
          {
              get
              {
                  var names = NamesLink.OfType<LastName>().ToList();
                  if (!names.Any())
                  {
                      foreach (LastName fn in names)
                      {
                          lastName = fn.Name.NameString;
                      }
                  }
                  return lastName;
              }
              set
              {
                  if (value != null)
                  {
                      var name = new Name { NameString = value };
                      var ln = new LastName { Name = name };
                      NamesLink.Add(new LastName { Name = name });
                      NamesLink.Add(ln);
                      lastName = value;
                  }
      
              }
          }
          private string? lastName;
      
          public DateTime DateOfBirth { get; set; }
      
          public string GetFullName()
          {
              return FirstName + " " + LastName;
          }
          public virtual ICollection<PeopleName> NamesLink { get; set; } = new Collection<PeopleName>();
      
      }
      

      【讨论】:

        猜你喜欢
        • 2020-03-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-18
        • 1970-01-01
        相关资源
        最近更新 更多