Do Entity Framework提供将DB类型转换为C#类型的实用程序

本文关键字:类型 实用程序 类型转换 DB Framework Entity Do | 更新日期: 2023-09-27 18:30:03

我正在使用反射和类型生成器等构建一个动态类,我想知道如何将类型转换为c#类型

目前我是这样做的,但EF提供这种东西吗?

 case "uniqueidentifier":
                return typeof(Guid);
            case "bit":
                return typeof(Boolean);
            case "nvarchar":
                return (typeof(string));
            case "datetime":
                return typeof(DateTime);
            case "float":
                return typeof(double);
            case "int":
                return (typeof(int));

感谢

更新我认为EF到目前为止还没有公开的公用设施。接受的答案与EF无关。那里的图书馆完全不同。

Ryszard Dżegan已经给出了答案,但它不能在TT模板或edmx之外使用(或者可能是我不知道的)

Do Entity Framework提供将DB类型转换为C#类型的实用程序

我不知道这样一个公共方法(我认为没有……它可以被接受作为答案)

然而,尝试解压缩sqlmetal.exe,您可以很好地了解默认关联是如何在内部实现的:

在类LinqToSqlShared.Utility.DbTypeSystem(内部类)中,可以找到方法:

internal static Type GetClosestRuntimeType(SqlDbType sqlDbType)
{
switch (sqlDbType)
{
    case SqlDbType.BigInt:
        return typeof(long);
    case SqlDbType.Binary:
    case SqlDbType.Image:
    case SqlDbType.Timestamp:
    case SqlDbType.VarBinary:
        return typeof(Binary);
    case SqlDbType.Bit:
        return typeof(bool);
    case SqlDbType.Char:
    case SqlDbType.NChar:
    case SqlDbType.NText:
    case SqlDbType.NVarChar:
    case SqlDbType.Text:
    case SqlDbType.VarChar:
        return typeof(string);
    case SqlDbType.DateTime:
    case SqlDbType.SmallDateTime:
    case SqlDbType.Date:
    case SqlDbType.DateTime2:
        return typeof(DateTime);
    case SqlDbType.Decimal:
    case SqlDbType.Money:
    case SqlDbType.SmallMoney:
        return typeof(decimal);
    case SqlDbType.Float:
        return typeof(double);
    case SqlDbType.Int:
        return typeof(int);
    case SqlDbType.Real:
        return typeof(float);
    case SqlDbType.UniqueIdentifier:
        return typeof(Guid);
    case SqlDbType.SmallInt:
        return typeof(short);
    case SqlDbType.TinyInt:
        return typeof(byte);
    case SqlDbType.Xml:
        return typeof(XElement);
    case SqlDbType.Time:
        return typeof(TimeSpan);
    case SqlDbType.DateTimeOffset:
        return typeof(DateTimeOffset);
}
return typeof(object);
}

编辑

  • 将此作为参考

  • 同一类中还有一个方法static SqlDbType Parse(string stype),它从sql类型字符串定义中返回枚举SqlDbType。

我可以假设,由于实体框架能够在概念模型和存储模型之间创建映射,因此它具有将每个数据库类型强制转换为相应概念类型的内部能力。

此外,实体框架在T4模板中使用EF.Utility.CS.ttinclude标头中存在的辅助类来生成上下文和实体源文件。

EF.Utility.CS.ttinclude反过来在内部使用System.Data.Metadata.Edm命名空间中的类,特别是PrimitiveTypeKind枚举,它涵盖概念类型并构成数据库类型和CLR类型之间的桥梁。

PrimitiveTypeKind枚举的值可以作为PrimitiveType类中的属性找到,该类还有另一个有趣的属性ClrEquivalentType,它按预期返回System.Type.

PrimitiveType类实例可以通过各种方式获取。在T4模板中,实体框架与具有GetPrimitiveTypes方法的EdmItemCollection类一起工作。

在T4模板中,访问EdmItemCollection类的最简单方法是使用MetadataLoader的(来自EF.Utility.CS.ttinclude)CreateEdmItemCollection-方法,该方法将edmx文件作为参数路径。

在tt文件中,你可以写:

<#@ template hostSpecific="true" #>
<#@ output extension=".txt" #>
<#@ include file="EF.Utility.CS.ttinclude" #><#
var edmxPath = "NorthwindModel.edmx"; // <--- Put the path to your model here.
var loader = new MetadataLoader(this);
var edmItemCollection = loader.CreateEdmItemCollection(edmxPath);
var primitiveTypes = edmItemCollection.GetPrimitiveTypes();
#>
<#
foreach (var primitiveType in primitiveTypes)
{
#>
<#= primitiveType#> ==> <#= primitiveType.ClrEquivalentType#>
<#
}
#>

结果将是:

Edm.Binary ==> System.Byte[]
Edm.Boolean ==> System.Boolean
Edm.Byte ==> System.Byte
Edm.DateTime ==> System.DateTime
Edm.Decimal ==> System.Decimal
Edm.Double ==> System.Double
Edm.Guid ==> System.Guid
Edm.Single ==> System.Single
Edm.SByte ==> System.SByte
Edm.Int16 ==> System.Int16
Edm.Int32 ==> System.Int32
Edm.Int64 ==> System.Int64
Edm.String ==> System.String
Edm.Time ==> System.TimeSpan
Edm.DateTimeOffset ==> System.DateTimeOffset
Edm.Geometry ==> System.Data.Spatial.DbGeometry
Edm.Geography ==> System.Data.Spatial.DbGeography
Edm.GeometryPoint ==> System.Data.Spatial.DbGeometry
Edm.GeometryLineString ==> System.Data.Spatial.DbGeometry
Edm.GeometryPolygon ==> System.Data.Spatial.DbGeometry
Edm.GeometryMultiPoint ==> System.Data.Spatial.DbGeometry
Edm.GeometryMultiLineString ==> System.Data.Spatial.DbGeometry
Edm.GeometryMultiPolygon ==> System.Data.Spatial.DbGeometry
Edm.GeometryCollection ==> System.Data.Spatial.DbGeometry
Edm.GeographyPoint ==> System.Data.Spatial.DbGeography
Edm.GeographyLineString ==> System.Data.Spatial.DbGeography
Edm.GeographyPolygon ==> System.Data.Spatial.DbGeography
Edm.GeographyMultiPoint ==> System.Data.Spatial.DbGeography
Edm.GeographyMultiLineString ==> System.Data.Spatial.DbGeography
Edm.GeographyMultiPolygon ==> System.Data.Spatial.DbGeography
Edm.GeographyCollection ==> System.Data.Spatial.DbGeography

在普通的C#代码中,若你们有MetadataLoader,你们也可以做同样的事情。要忽略这个障碍,只需将MetadataLoader类复制到代码中即可。然而,实现这一目标也有其他方法。如果使用"代码优先"方法,那么有趣的解决方案是使用EdmxWriter.WriteEdmx方法(DbContext,XmlWriter)在MemoryStream中动态创建edmx文件,然后将该流作为参数放入XmlReader.create方法(stream)中,最后在EdmItemCollection构造函数(IEnumerable)中使用xml读取器作为输入参数。

也有用C#类型替换CLR类型的方法(Nullable<System.Int32>===>int?),但情况不同。。。