C# 在实体POCO中使用自定义数据类型?

C# 在实体POCO中使用自定义数据类型?,c#,entity-framework-4.1,poco,C#,Entity Framework 4.1,Poco,我有一个业务对象,比如用户。用户有一个电话号码字段,由字符串表示。一、 出于最好留给我的原因,我创建了一个PhoneNumber类,该类具有隐式的to/from字符串运算符。要将PhoneNumber作为字符串写入数据库,我需要做什么特殊的事情吗?现在,实体已经决定将我的PhoneNumber类分解为它的组成部分(AreaCode,前缀,等等),并将它们分别保存到数据库中电话号码存储在单独的程序集中 public class PhoneNumber : IEquatable<PhoneNu

我有一个业务对象,比如
用户
用户
有一个
电话号码
字段,由字符串表示。一、 出于最好留给我的原因,我创建了一个
PhoneNumber
类,该类具有隐式的to/from字符串运算符。要将
PhoneNumber
作为字符串写入数据库,我需要做什么特殊的事情吗?现在,实体已经决定将我的
PhoneNumber
类分解为它的组成部分(
AreaCode
前缀
,等等),并将它们分别保存到数据库中<代码>电话号码存储在单独的程序集中

public class PhoneNumber : IEquatable<PhoneNumber>, IComparable<PhoneNumber>
{
    public static implicit operator string (PhoneNumber ph)
    {
        return ph.ToString ();
    }

    public static implicit operator PhoneNumber (string number)
    {
        return Parse(number);
    }

    public static PhoneNumber Parse(string number)
    {
       // ...
    }

    public override string ToString ()
    {
        // produce a Parse-compatible output
    }
}

public class User
{
    public virtual int Id { get; set; }
    public virtual string FirstName { get; set; }
    public virtual PhoneNumber Phone { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<User> Users { get; set; }
}
公共类电话号码:IEquatable,IComparable
{
公共静态隐式运算符字符串(PhoneNumber ph)
{
返回ph.ToString();
}
公共静态隐式运算符PhoneNumber(字符串编号)
{
返回解析(数字);
}
公共静态电话号码解析(字符串号码)
{
// ...
}
公共重写字符串ToString()
{
//生成与解析兼容的输出
}
}
公共类用户
{
公共虚拟整数Id{get;set;}
公共虚拟字符串FirstName{get;set;}
公共虚拟电话号码电话{get;set;}
}
公共类MyContext:DbContext
{
公共数据库集用户{get;set;}
}

唯一的解决办法是:

// You want to store in same table and not a navigation property, right?
// Then you need [ComplexType]
[ComplexType] 
public class PhoneNumber : IEquatable<PhoneNumber>, IComparable<PhoneNumber>
{
    // ...

    public string FullNumber
    {
        get
        {
            return Prefix + "-" + AreaCode + " " + Number; // or whatever
        }
        set
        {
            AreaCode = ParseToAreaCode(value); // or so...
            Prefix = ParseToPrefix(value);     // or so...
            Number = ParseToNumber(value);     // or so...
        }
    }

    [NotMapped]
    public string AreaCode { get; set; }
    [NotMapped]
    public string Prefix { get; set; }
    [NotMapped]
    public string Number { get; set; }
}
//您希望存储在同一个表中,而不是导航属性,对吗?
//然后您需要[ComplexType]
[复合类型]
公共类电话号码:IEquatable、IComparable
{
// ...
公共字符串完整编号
{
得到
{
返回前缀+“-”+区号+“”+数字;//或其他
}
设置
{
AreaCode=ParseToAreaCode(值);//大约。。。
Prefix=ParseToPrefix(值);//大约。。。
Number=parsetNumber(值);//大约。。。
}
}
[未映射]
公共字符串区域代码{get;set;}
[未映射]
公共字符串前缀{get;set;}
[未映射]
公共字符串编号{get;set;}
}

这样,您将在数据库中只获得一个
FullNumber
列。

唯一的方法是这样的解决方法:

// You want to store in same table and not a navigation property, right?
// Then you need [ComplexType]
[ComplexType] 
public class PhoneNumber : IEquatable<PhoneNumber>, IComparable<PhoneNumber>
{
    // ...

    public string FullNumber
    {
        get
        {
            return Prefix + "-" + AreaCode + " " + Number; // or whatever
        }
        set
        {
            AreaCode = ParseToAreaCode(value); // or so...
            Prefix = ParseToPrefix(value);     // or so...
            Number = ParseToNumber(value);     // or so...
        }
    }

    [NotMapped]
    public string AreaCode { get; set; }
    [NotMapped]
    public string Prefix { get; set; }
    [NotMapped]
    public string Number { get; set; }
}
//您希望存储在同一个表中,而不是导航属性,对吗?
//然后您需要[ComplexType]
[复合类型]
公共类电话号码:IEquatable、IComparable
{
// ...
公共字符串完整编号
{
得到
{
返回前缀+“-”+区号+“”+数字;//或其他
}
设置
{
AreaCode=ParseToAreaCode(值);//大约。。。
Prefix=ParseToPrefix(值);//大约。。。
Number=parsetNumber(值);//大约。。。
}
}
[未映射]
公共字符串区域代码{get;set;}
[未映射]
公共字符串前缀{get;set;}
[未映射]
公共字符串编号{get;set;}
}

这样,您将在数据库中只获得一个
FullNumber
列。

如果您的其他设计允许,您可以将
PhoneNumber
类从映射中排除,并让
User
处理它的字符串表示,如:

public class User
{
  public virtual int Id { get; set; }
  public virtual string FirstName { get; set; }

  public virtual string PhoneNumber
  { 
      get { return this.PhoneNumber.ToString(); } // TODO: check for null
      set { this.PhoneNumber = PhoneNumber.Parse(value); }
  }

  [NotMapped]
  public virtual PhoneNumber Phone { get; set; }
}

如果设计的其余部分允许,您可以将
PhoneNumber
类从映射中排除,并让
User
处理它的字符串表示,如:

public class User
{
  public virtual int Id { get; set; }
  public virtual string FirstName { get; set; }

  public virtual string PhoneNumber
  { 
      get { return this.PhoneNumber.ToString(); } // TODO: check for null
      set { this.PhoneNumber = PhoneNumber.Parse(value); }
  }

  [NotMapped]
  public virtual PhoneNumber Phone { get; set; }
}

Entityframework使用实体类并将每个属性表示为列,工作正常。您的PhoneNumber类是部分的吗?如果是,您可以在PhoneNumber类的none-generated部分中重写ToString()。这样一来,无论它如何存储在数据库中,对象都可以为您提供这些信息。它不是一个分部类,但对象确实重写了ToString(),并产生了我所期望的结果。我将更新一些示例代码。好吧,我想问题是,为什么要将电话号码存储为字符串而不是实体表示形式。EF总是将属性转换为列或列转换为属性,这取决于您是否先编写代码。在数据库中,有5列专门用于存储电话号码的数据块,而不是规范的“(101)555-1234”表示形式,这很尴尬。也许没什么大不了的?有什么尴尬的?拥有3个单独的字段将强制执行该格式,并允许每个应用程序以其想要的任何格式在内部显示字段。否则,您将需要担心101.555.1234对101-555-1234对(101)555-1234对1015551234。使用一个列,您将如何查询给定区号、exchange、国家/地区代码等的所有记录。如果将这些查询存储在部分中,则所有这些查询都更易于编写。Entityframework使用实体类并将每个属性表示为列,工作正常。您的PhoneNumber类是部分的吗?如果是,您可以在PhoneNumber类的none-generated部分中重写ToString()。这样一来,无论它如何存储在数据库中,对象都可以为您提供这些信息。它不是一个分部类,但对象确实重写了ToString(),并产生了我所期望的结果。我将更新一些示例代码。好吧,我想问题是,为什么要将电话号码存储为字符串而不是实体表示形式。EF总是将属性转换为列或列转换为属性,这取决于您是否先编写代码。在数据库中,有5列专门用于存储电话号码的数据块,而不是规范的“(101)555-1234”表示形式,这很尴尬。也许没什么大不了的?有什么尴尬的?拥有3个单独的字段将强制执行该格式,并允许每个应用程序以其想要的任何格式在内部显示字段。否则,您将需要担心101.555.1234对101-555-1234对(101)555-1234对1015551234。使用一列,您将如何查询