Entity-Framework 5.0 を PostgreSql データベースの O/R マッパーとして使用したいと考えています。すでに多くのハウツーを読みましたが、まだ行き詰っています。たぶん、私は 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; }
}
app.config:
<?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 ツールによって生成された Entity Customer クラス:
/// <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 プロパティからメタデータ キーワードを削除すると、次のエラーが発生します。
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 から、メタデータ、プロバイダー、およびプロバイダー接続文字列プロパティを削除しました。ブライスが言ったように、メタデータ ファイルは必要ないので、削除しました。
また、Device および Customer クラスの Table-Attribute はスキーマを指定する必要があります。このような:
[Table("customer", Schema="public")]
public class Customer