EF Code First Reverse Engineering Customized templates (EF Power Tools Beta 2 ) - entity-framework-4

I'm in the process of generating POCOs from an existing pgsql database.
I want to put the generated POCOs into an own C# class library and the DbContext and mapping into a
different project so that my POCOs have no referance to anything EF related.
I'm trying to modify the Context.tt template to specify the table schema at runtime during OnModelCreating(), because using a [Table] attribute on the generated entities would introduce a hard link to the EF library.
My problem is that I'm currently unable to retrieve the schema name from the current EnitySet.
Here is an extract of What I've done so far :
var efHost = (EfTextTemplateHost)Host;
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
<#
foreach (var set in efHost.EntityContainer.BaseEntitySets.OfType<EntitySet>())
{
#>
modelBuilder.Configurations.Add(new <#= set.ElementType.Name #>Map());
modelBuilder.Entity<<#= set.ElementType.Name #>>().ToTable("<#= set.Name #>", "<#=????#>");
<#
}
#>
}
The only object available at this time is an instance of EfTextTemplateHost.
Any Help Appreciated.
TIA.
EDIT : I've found the way to retreive the schema (set.MetadataProperties["Schema"].Value ?? ""), but the value is always null !
This may imply that the Reverse Enginering Code First tool does not give the value to the template host. I may end parsing an edmx file. To be continued.

I looked at the mapping.tt file that comes with the power tools, and it gets the schema by doing this:
var tableSet = efHost.TableSet;
var tableName = (string)tableSet.MetadataProperties["Table"].Value
?? tableSet.Name;
var schemaName = (string)tableSet.MetadataProperties["Schema"].Value;
Could you do something similar? Maybe this (haven't tried this myself):
<#
foreach (var set in efHost.EntityContainer.BaseEntitySets.OfType<EntitySet>())
{
#>
modelBuilder.Configurations.Add(new <#= efHost.TableSet.MetadataProperties[set.ElementType.Name].Value #>Map());
modelBuilder.Entity<<#= efHost.TableSet.MetadataProperties[set.ElementType.Name].Value #>>().ToTable("<#= set.Name #>", "<#=efHost.TableSet.MetadataProperties[set.ElementType.Name].Value #>");
<#
}
#>

Related

EF migration Seeding with large dataset

I am using EF Code First Migration with ASP.NET MVC5 project. I want to seed the database with about 5000 records. The examples on the asp.net web site and blogs all have the seed function within the configuration method.
internal sealed class Configuration : DbMigrationsConfiguration<foo.ApplicationDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
MigrationsDirectory = #"Migrations\ApplicationDbContext";
}
protected override void Seed(foo.ApplicationDbContext context)
{
SeedProducts(context);
SeedFoods(context);
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data. E.g.
//
// context.People.AddOrUpdate(
// p => p.FullName,
// new Person { FullName = "Andrew Peters" },
// new Person { FullName = "Brice Lambson" },
// new Person { FullName = "Rowan Miller" }
// );
//
}
}
What are some options to seed large data sets when using EF Migration?
Currently The configuration file is over 5000 lines long and is different to manage.
I would prefer to store them in another database or excel spreadsheet and then import them in using the seed function. I am not sure how to go about importing data from external sources within the Seed method.
I also tried to break up the data set into several files but when I try to call the function
SeedProducts(context);
SeedFoods(context);
outside of the Configuration Class I get a build error: "The name does not exists in the current context". (I am not sure what this means?
You can store the sql file in the base directory and use it. You can create multiple sql files. I used following code to execute all sql files stored on base directory.
protected override void Seed(CRM.Data.DbContexts.CRMContext context)
{
var sqlfiles = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory+"\\initialdata", "*.sql");
sqlfiles.ToList().ForEach(x=> context.Database.ExecuteSqlCommand(File.ReadAllText(x)));
}
Why we need to have a seed data for 5000 records. If you prefer this way it will take lot of manual work also. where as, its not required here.
Instantly you can Create Scripts and execute that into you db. via Code as well as Manually.
Db Scripts can be taken for entire db as well as each table, Store Procedure wise also. So, that you will get records particularly.
Follow the steps from this link OR MSDN
Note: After Creating the Database Script. You can read the file from Seed Function and Execute the query from function itself. Or Manually you can go and execute when ever you need it.
I ended up using a CSV (comma delimited file) and storing it as a domain resource. Then reading the CSV file and adding database records:
I am able to Seed the database using EF Migration Seed method and a CSV file as defined as follows in the Migration.cs file. Note: the CSV file in the project in Visual Studio are set to the Build Action to Embedded Resource.
public void SeedData(WebApp.Models.ApplicationDbContext Context)
{
Assembly assembly = Assembly.GetExecutingAssembly();
string resourceName = "WebApp.SeedData.Name.csv";
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
{
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
{
CsvReader csvReader = new CsvReader(reader);
csvReader.Configuration.WillThrowOnMissingField = false;
var records = csvReader.GetRecords<Products>().ToArray();
foreach (Product record in records)
{
Context.Products.AddOrUpdate(record);
}
}
}
Context.SaveChanges();
}

Calling Stored Procedure From Entity Framework that returns table with variable columns

I am using ASP.NET MVC 3 and EF 4.x
I have a procedure that returns a result set but the columns are not fixed (it may return 25 columns or may be 40 or 50).
How can I call this stored procedure from Entity Framework?
When I use function import it asks for an Entity. But I cannot select it as none of the columns is fixed.
Entity Framework is not the right tool for this. It is good at statically defined data structures, not at dynamic ones.
There are better tools for this. I would recommend Dapper, created by Marc Gravell. It's easy as pie. Just get the NuGet package and type something like
using Dapper;
using (var cnn = new SqlConnection(myConnectionString))
{
cnn.Open();
var p = new DynamicParameters();
p.Add("#params", "Id=21");
var results = cnn.Query(sql:"GetMyData",
param: p,
commandType: CommandType.StoredProcedure);
foreach(IDictionary<string, object> result in results)
{
// Do something here.
}
}
Query is a Dapper extension method, result is a DapperRow, which is a private class that implements IDictionary<string, object>, so you can just access your data as a dictionary per record.
Aside from being easy to use, it's lightning fast too.

db4o - how do I get a distinct list of classes contained in a .db4o DB file?

Say I open a .db4o file. What would be the Java code (psuedo) that would generate a list of unique Java CLASSES/TYPES contained in the database?
I am sure I could write the code to do it, but I am afraid it could be quite slow. Is there a good way to do this without querying for every object in the database? Could I use some sort of index?
I'd rather not rely on stored metadata about the database, I'd rather rely on the true information about what objects are actually stored within.
You can use something like (C# but it can be easily converted to Java :)
const string DatabaseFileName = "c:\\temp\\Learning.odb";
static void Main(string[] args)
{
using (var db = Db4oEmbedded.OpenFile(DatabaseFileName))
{
var classes = db.Ext().StoredClasses();
foreach (var #class in classes)
{
Console.WriteLine();
Console.WriteLine(#class.GetName());
foreach (var field in #class.GetStoredFields())
{
Console.WriteLine("\t{1} {0}", field.GetName(), field.GetStoredType().GetName());
}
}
}
}
Note that you have more interesting methods in ExtObjectContainer interface.
Hope this helps.

Breeze BeforeSaveEntities: how to modify savemap

I read the following from the Breeze documentation about BeforeSaveEntities:
"Entities may be added or removed from the map returned by this method".
So I suppose I can add a new instance of EntityInfo to the saveMap.
My question is: how can I do that? Is there any example of that anywhere?
I can perfectly loop through the dictionary. But since EntityInfo has no constructor, and all its fields are get only, I feel a bit stuck here. Any help is welcome.
Thanks
Ok, here is a very contrived example of a BeforeSaveEntities override that creates comment records alongside a whatever is normally saved. Comment records include a comment generated based on the value of the SaveOptions.Tag property.
protected override Dictionary<Type, List<EntityInfo>> BeforeSaveEntities(Dictionary<Type, List<EntityInfo>> saveMap) {
var comment = new Comment();
var tag = ContextProvider.SaveOptions.Tag;
comment.Comment1 = (tag == null) ? "Generic comment" : tag.ToString();
comment.CreatedOn = DateTime.Now;
comment.SeqNum = 1;
var ei = ContextProvider.CreateEntityInfo(comment);
List<EntityInfo> comments;
if (!saveMap.TryGetValue(typeof(Comment), out comments)) {
comments = new List<EntityInfo>();
saveMap.Add(typeof(Comment), comments);
}
comments.Add(ei);
return saveMap;
}
}
This answer is for those developers that have chosen to use Database First using an objectContext instead of Code First, and for Nicolas.
I found after using the Breeze Source Code in Debug that line 805 of the GetEntitySetName method (cspaceEntityType = cspaceEntityTypes.First(et => et.FullName == entityType.FullName)
I would get the error "Sequence contains no matching element"
I noticed inside my watch that et.FullName and entityType.FullName did not have the same namespace. This told my comrad and I that the edmx models namespace was not the same as the object context.
Go to your edmx model select right click inside the empty space and select properties. ensure that the Namespace property is the same as your Object Context.

Entity Framework CTP5 - Reading Multiple Record Sets From a Stored Procedure

In EF4, this was not easily possible. You either had to degrade to classic ADO.NET (DataReader), use ObjectContext.Translate or use the EFExtensions project.
Has this been implemented off the shelf in EF CTP5?
If not, what is the recommended way of doing this?
Do we have to cast the DbContext<T> as an IObjectContextAdapter and access the underlying ObjectContext in order to get to this method?
Can someone point me to a good article on doing this with EF CTP5?
So i got this working, here's what i have:
internal SomeInternalPOCOWrapper FindXXX(string xxx)
{
Condition.Requires(xxx).IsNotNullOrEmpty();
var someInternalPokey = new SomeInternalPOCOWrapper();
var ctx = (this as IObjectContextAdapter).ObjectContext;
var con = new SqlConnection("xxxxx");
{
con.Open();
DbCommand cmd = con.CreateCommand();
cmd.CommandText = "exec dbo.usp_XXX #xxxx";
cmd.Parameters.Add(new SqlParameter("xxxx", xxx));
using (var rdr = cmd.ExecuteReader())
{
// -- RESULT SET #1
someInternalPokey.Prop1 = ctx.Translate<InternalPoco1>(rdr);
// -- RESULT SET #2
rdr.NextResult();
someInternalPokey.Prop2 = ctx.Translate<InternalPoco2>(rdr);
// -- RESULT SET #3
rdr.NextResult();
someInternalPokey.Prop3 = ctx.Translate<InternalPoco3>(rdr);
// RESULT SET #4
rdr.NextResult();
someInternalPokey.Prop4 = ctx.Translate<InternalPoco4>(rdr);
}
con.Close();
}
return someInternalPokey;
}
Essentially, it's basically like classic ADO.NET. You read the DbReader, advance to the next result set, etc.
But at least we have the Translate method which seemingly does a left-to-right between the result set fields and the supplied entity.
Note the method is internal.
My Repository calls this method, then hydrates the DTO into my domain objects.
I'm not 100% happy with it for 3 reasons:
We have to cast the DbContext as IObjectContextAdapter. The method Translate should be on DbContext<T> class IMO.
We have to use classic ADO.NET Objects. Why? Stored Procedures are a must have for any ORM. My main gripe with EF is the lack of the stored procedure support and this seems to not have been rectified with EF CTP5.
You have to open a new SqlConnection. Why can't it use the same connection as the one opened by the EF Context?
Hope this both helps someone and sends out a message to the EF team. We need multiple result support for SPROCS off the shelf. You can map a stored proc to a complex type, so why can't we map a stored proc to multiple complex types?

Resources