我想将 Entity-Framework 5.0 用作带有 PostgreSql 数据库的 O/R 映射器。我已经阅读了很多 HowTos,但我仍然卡住了。也许我不明白 EF 背后的全部想法。
我想要的是:
- 我想自己写代码。然后将一些属性添加到属性和类中,以告诉 EF 如何映射对象(就像我对 NHibernate 所做的那样)。
- 我不想从我的模型生成数据库 - 我只想使用现有的。
示例模型:
[Table("device")]
public class Device
{
[Key]
public int Id { get; set; }
[StringLength(255)]
public string Identifier { get; set; }
}
[Table("customer")]
public class Customer
{
public Customer()
{
this.Devices = new List<Device>();
}
[Key]
public int Id { get; set; }
[StringLength(255)]
public string Name { get; set; }
// attribute required?
public List<Device> Devices { get; set; }
}
我做了什么:
- 写了上面的代码
- 创建了一个 DatabaseContext 类
- 在 app.config 中添加了 DbProviderFactories 和 connectionStrings
- 用 EdmGen.exe 工具生成 ssdl、msl、csdl 文件并复制到项目中(这些文件在 bin 文件夹中也有)
数据库上下文:
public class DatabaseContext : DbContext
{
static DatabaseContext()
{
Database.SetInitializer<DatabaseContext>(null);
}
public DatabaseContext()
: base("PostgreSQL")
{
}
public DbSet<Customer> Customers { get; set; }
public DbSet<Device> Devices { get; set; }
}
应用程序配置:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.data>
<DbProviderFactories>
<remove invariant="Npgsql" />
<add name="Npgsql Data Provider" invariant="Npgsql" support="FF" description=".Net Framework Data Provider for Postgresql Server" type="Npgsql.NpgsqlFactory, Npgsql, Version=2.0.12.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7" />
</DbProviderFactories>
</system.data>
<connectionStrings>
<add name="PostGreSQL"
providerName="System.Data.EntityClient"
connectionString="metadata=.;provider=Npgsql;provider connection string="Server=asdf;Port=5432;User Id=asdf;Password=asdf;Database=asdf;enlist=true"" />
</connectionStrings>
</configuration>
测试:
using (DatabaseContext context = new DatabaseContext())
{
if (context.Database.Exists())
{
Console.WriteLine("yep");
}
else
{
Console.WriteLine("nope");
}
foreach (Customer c in context.Customers)
{
Console.WriteLine("Name={0}", c.Name);
}
}
Console.ReadLine();
输出和错误:
“是的” .. 这意味着数据库存在。但是当访问 context.Customers 属性时,我得到以下异常:
The entity type Customer is not part of the model for the current context.
堆栈跟踪:
at System.Data.Entity.Internal.InternalContext.UpdateEntitySetMappingsForType(Type entityType)
at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
at System.Data.Entity.Internal.Linq.InternalSet`1.GetEnumerator()
at System.Data.Entity.Infrastructure.DbQuery`1.System.Collections.Generic.IEnumerable<TResult>.GetEnumerator()
at EF5.Program.Main(String[] args) in c:\Users\tba\Documents\Visual Studio 2012\Projects\EF5\EF5\Program.cs:line 26
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
我不明白的是:
- 如果 DataAnnoations 可用,ssdl、msl、csdl 文件有什么用?
- 为什么 Customer 类不是当前上下文模型的一部分?
当使用 EdmGen.exe 工具时,它还会生成一个包含 ObjectContext 和实体类的 ObjectLayer.cs 文件。问题在于,实体类派生自 EntityObject。如果我想将实体类用作业务类,这是一个严重的问题,因为这些类不能从任何其他类派生。
此外,我不明白为什么它会生成一个 ObjectContext.. 我发现的每一个 HowTo 都使用 DbContext 类。
EdmGen 工具生成的实体客户类:
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmEntityTypeAttribute(NamespaceName="EF5", Name="Customer")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
public partial class Customer : EntityObject
我很困惑 :-)
编辑:
- 我没有使用 ObjectLayer.cs 文件!由于我上面提到的继承问题,我也不想使用它。部分 Customer 类只是显示 EdmGen 工具生成内容的示例。
当我删除 csdl、msl 和 ssdl 文件时,我收到以下错误:
At least one SSDL artifact is required for creating StoreItemCollection.
当我从 app.config 中的 connectionString 属性中删除 metadata 关键字时,我收到以下错误:
Some required information is missing from the connection string. The 'metadata' keyword is always required.
解决方案:
我终于弄清楚它是如何工作的。app.config 中的 connectionString 错误。正确的连接字符串:
<connectionStrings>
<add name="PostgreSQL"
connectionString="Server=asdf;Port=5432;User Id=asdf;Password=asdf;Database=asdf;"
providerName="Npgsql" />
</connectionStrings>
我从 connectionString 中删除了元数据、提供程序和提供程序连接字符串属性。就像Brice所说,元数据文件不是必需的,所以我只是删除了它们。
Device 和 Customer 类的 Table-Attribute 也需要指定schema。像这样:
[Table("customer", Schema="public")]
public class Customer