Getting the entity mapped table name using T4 - entity-framework

I am trying to use T4 to generate code for the following:
public virtual IList<Frequency> GetAll()
{
using (var wc = new WCDataClassesDataContext())
{
return wc.Frequencies.ToList();
}
}
public virtual IList<Frequency> GetAll(Expression<Func<Frequency, bool>> whereClause)
{
using (var wc = new WCDataClassesDataContext())
{
return wc.Frequencies.Where(whereClause).ToList();
}
}
In T4 i am using:
foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection))
{
fileManager.StartNewFile(entity.Name + "BaseFinder.cs");
BeginNamespace(code);
#>
<#=codeStringGenerator.UsingDirectives(inHeader: false)#>
using System.Linq;
using System.Linq.Expressions;
<#=codeStringGenerator.EntityClassOpening(entity)#>
{
public virtual IList<<#=entity.Name #>> GetAll()
{
using (var wc = new WCDataClassesDataContext())
{
return wc.[[Frequencies]].ToList();
}
}
public virtual IList<<#=entity.Name #>> GetAll(Expression<Func<<#=entity.Name #>, bool>> whereClause)
{
using (var wc = new WCDataClassesDataContext())
{
return wc.[[Frequencies]].Where(whereClause).ToList();
}
}
......
}
Instead of [[Frequencies]] i want the main table name that the entity is mapped to.
I am trying to setup various getters which can be used easily in the classes.
Could you tell me what is the solution to do this, or there could be some other way to do this?
Hope you got my point.
Thanks.

It looks like you have the entity type already, so I think you're close - all you need to do is get the navigation properties that have a relationship multiplicity of many, and you should be set.
Something like:
EntityType et = entity.GetType();
foreach(var navProp in et.NavigationProperties.Where(np=>np.DeclaringType == et
&& np.RelationshipMultiplicity == RelationshipMultiplicity.Many))
{
string s = string.Format("public virtual IList<{0}> GetAll() ...",
navProp.ToEndMember.GetEntityType().Name);
}
The Entity Framework DB-first generator already does a flavor of this; if you go digging around under the EDMX, you should see a *.Context.tt or something similar. In there, do a search for NavigationProperty, there is a code string helper method to generate something similar.

Related

How to create generic EF Insert method?

I'd like to create a generic C# class with a method that will add a row to a database using Entity Framework.
I have one table called Address. I've written the following code to add an address to the database:
public class AddressExchange
{
public int Insert(Address address)
{
using (var db = new DemoWebEntities())
{
//db.AddObject("Address", address);
db.Addresses.AddObject(address);
db.SaveChanges();
return address.Id;
}
}
}
I would like to write a generic class that will perform this operation for any entity in my EDMX. I think that it should look something like this:
public class EntityExchange<T, KeyType>
{
public KeyType Insert(T t)
{
using (var db = new DemoWebEntities())
{
// The entity set name might be wrong.
db.AddObject(typeof(T).Name, t);
// EF doesn't know what the primary key is.
return t.Id;
}
}
}
I think it may be possible to use the AddObject method to add the object to the database, but the entityset name is not necessarily the same as the type name, especially if it has been pluralized!
I also want to return the primary key to the caller, but I don't know how to tell which field contains the primary key.
I have a generic InsertOrUpdate method in a generic repository that also ensures proxies are created. (Proxies are required to support lazy loading and if you create an entity using "new", then proxies are not created). See the question here
public class RepositoryBase<T> : IRepository<T> where T : ModelBase
{
public virtual T InsertOrUpdate(T e)
{
DbSet<T> dbSet = context.Set<T>();
//Generate a proxy type to support lazy loading
T instance = dbSet.Create();
DbEntityEntry<T> entry;
if (e.GetType().Equals(instance.GetType()))
{
//The entity being added is already a proxy type that
//supports lazy loading just get the context entry
entry = context.Entry(e);
}
else
{
//The entity being added has been created using the "new" operator.
//Attach the proxy
//Need to set the ID before attaching or we get
//The property 'ID' is part of the object's key
//information and cannot be modified when we call SetValues
instance.ID = e.ID;
entry = context.Entry(instance);
dbSet.Attach(instance);
//and set it's values to those of the entity
entry.CurrentValues.SetValues(e);
e = instance;
}
entry.State = e.ID == default(int) ?
EntityState.Added :
EntityState.Modified;
return e;
}
}
public abstract class ModelBase
{
public int ID { get; set; }
}
Note that all the models inherit ModelBase so that handles the ID issue and I return the entity rather than just the ID. That is probably not strictly necessary since a reference to the entity is passed in and EF performs fixup on the ID anyway so you can always access it from the refernce passed in.
This might be reliant on a particular version on Entity framework however this is how I do it
public void Create(T entity)
{
using (var db = new DemoWebEntities())
{
db.Set<T>().Add(entity);
}
}
For the primary key issue, can you use partial classes to make your entities implement an interface, something like this:
public interface IEntity
{
Guid PrimaryKey { get; }
}
Your entity classes would then return the appropriate value:
public partial class EntityType : IEntity
{
public Guid PrimaryKey
{
get
{
return this.WhateverId; // Return the primary key
}
}
}
Then, constrain your method to only accept IEntity:
public class EntityExchange<T, KeyType> where T : IEntity
And finally return the primary key after the insert:
return t.PrimaryKey;
May be it can help you.
public T Add(T model)
{
using (BigConceptEntities entity = new BigConceptEntities())
{
entity.Set<T>().Add(model);
entity.SaveChanges();
return model;
}
}

Decoupling Entity Framework from my POCO classes

I'm dynamically creating my DbContext by iterating over any entities that inherit from EntityBase and adding them to my Context:
private void AddEntities(DbModelBuilder modelBuilder)
{
var entityMethod = typeof(DbModelBuilder).GetMethod("Entity");
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
var entityTypes = assembly.GetTypes()
.Where(x => x.IsSubclassOf(typeof(EntityBase)) && !x.IsAbstract);
foreach (var type in entityTypes)
{
dynamic entityConfiguration = entityMethod.MakeGenericMethod(type).Invoke(modelBuilder, new object[] { });
EntityBase entity = (EntityBase)Activator.CreateInstance(type);
//Add any specific mappings that this class has defined
entity.OnModelCreating(entityConfiguration);
}
}
}
That way, I can have many namespaces but just one generic repository in my base namespace that's used everywhere. Also, in apps that make use of multiple namespaces, the base repository will already be setup to use all the entities in all the loaded namespaces. My problem is, I don't want to make EntityFramework.dll a dependency of every namespace in the company. So I'm calling OnModelCreating and passing the EntityTypeConfiguration to the class so it can add any mappings. This works fine and here's how I can add a mapping to tell the model that my "Description" property comes from a column called "Descriptor":
class Widget... {
public override void OnModelCreating(dynamic entity)
{
System.Linq.Expressions.Expression<Func<Widget, string>> tmp =
x => x.Description;
entity.Property(tmp).HasColumnName("Descriptor");
}
The good thing is, my entity class has no reference to EF, this method is only called once, when the context is created and if we scrap EF and go to something else in the future, my classes won't have all sorts of attributes specific to EF in them.
The problem is, it's super ugly. How can I let the model know about column mappings and keys in a simpler way than creating these Expressions to get properties to map without hard coding references to EF all over my poco classes?
You could define your own Attributes and use these to control the configuration within OnModelCreating(). You should be able to gain (using reflection) all the details you need for column mapping in one linq query a second query for the creation of the key.
public class DatabaseNameAttribute : Attribute
{
private readonly string _name;
public DatabaseNameAttribute(string name)
{
_name = name;
}
public string Name
{
get
{
return _name;
}
}
}
public class KeySequenceAttribute : Attribute
{
private readonly int _sequence;
public KeySequenceAttribute(int sequence)
{
_sequence = sequence;
}
public int Sequence
{
get
{
return _sequence;
}
}
}
[DatabaseName("BlogEntry")]
public class Post
{
[DatabaseName("BlogId")]
[KeySequence(1)]
public int id { get; set; }
[DatabaseName("Description")]
public string text { get; set; }
}

Entity Framework: Generic compare type without Id?

Is there anyway to do a comparison between objects for equality generically without objects having an ID?
I am trying to do a typical generic update, for which I have seen many examples of online, but they all usually look something like this:
public void Update(TClass entity)
{
TClass oldEntity = _context.Set<TClass>().Find(entity.Id);
foreach (var prop in typeof(TClass).GetProperties())
{
prop.SetValue(oldEntity, prop.GetValue(entity, null), null);
}
}
or something similar.The problem with my system is that not every class has a property named Id, depending on the class the Id can be ClassnameId. So is there anyway for me to check for the existence of and return such an entity via LINQ without supplying any properties generically?
Try
public void Update(TClass entity)
{
var oldEntry = _context.Entry<TClass>(oldEntity);
if (oldEntry.State == EntityState.Detached)
{
_context.Set<TClass>().Attach(oldEntity);
}
oldEntry.CurrentValues.SetValues(entity);
oldEntry.State = EntityState.Modified;
}

EF 4.1, POCO: Is any way to get Table name in runtime to avoid hardcode?

I use POCO in Entity Framework. Is any direct or indirect way in the latest EF version to get Table name at the runtime to avoid hardcode values?
I need it inside my custom database initializer to run code like this:
context.Database.ExecuteSqlCommand(
string.Format("DBCC CHECKIDENT ({0}, RESEED, {1})", tableName, newSeed))
Thanks
I'm working from the assumption that your context looks something like mine, with each of the table names getting generated from the class names when you add a DbSet to your context. If that's the case, you can achieve your goal with reflection, though it's a little ugly:
public class MyContext : DbContext
{
public MyContext() : base("MyDatabase")
{
}
public DbSet<Video> Video { get; set; }
public DbSet<VideoRating> Rating { get; set; }
public DbSet<User> User { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
public class Initializer : IDatabaseInitializer<DashVaultContext>
{
public void InitializeDatabase(MyContext context)
{
if (!context.Database.Exists())
{
context.Database.Create();
PropertyInfo[] propertyInfos = typeof(MyContext).GetProperties(BindingFlags.DeclaredOnly |
BindingFlags.Public | BindingFlags.Instance);
var newSeed = 1000; // Or whatever is appropriate
foreach (PropertyInfo propertyInfo in propertyInfos)
{
var tableName = propertyInfo.PropertyType.GetGenericArguments()[0].Name;
context.Database.ExecuteSqlCommand(
string.Format("DBCC CHECKIDENT ({0}, RESEED, {1})", tableName, newSeed));
}
}
}
}
}
UPDATE: I removed the pluralization hack and just turned off pluralization in the generated table names (see the OnModelCreating override).
POCO means you can use "plain-old" CLR objects (POCO), such as existing domain objects, with your data model. These POCO data classes (also known as persistence-ignorant objects), which are mapped to entities that are defined in a data model and by definition it shouldn't be directly related to database implementation details. However, you can use constant class and Fluent mapping to facilitate your requirement in a better way
Your constant class implementation
public static class Constant
{
public const string CreditCustomer = "dbo.CreditCustomer";
}
Your mappings goes like this
builder.Entity<Customer>()
.HasKey(c => c.ID)
.MapSingleType(c => new {
cid = c.ID,
nme = c.Name
}
)
.ToTable(Constant.Table.CreditCustomer);
In your dbInitializer
context.Database.ExecuteSqlCommand(
string.Format("DBCC CHECKIDENT ({0}, RESEED, {1})", Constant.Table.CreditCustomer, newSeed))
Looking at how "active" this discussion is, it seems to me this functionality is just not provided in the current version of EF. I hope this features will be available in one of future version of EF.
Will this code be useful at all?
var query = from meta in context.MetadataWorkspace.GetItems(DataSpace.SSpace)
.Where(m => m.BuiltInTypeKind == BuiltInTypeKind.EntityType)
let properties = meta is EntityType ? (meta as EntityType).Properties : null
select new
{
TableName = (meta as EntityType).Name,
Fields = from p in properties
select new
{
FielName = p.Name,
DbType = p.TypeUsage.EdmType.Name
}
};

Entity framework 4, Dynamic query

Is it possible to create a dynamic query with Entity Framework. I Have 18 tables, Each of them has the same structures. How can I create a dynamic query to reuse the same query for each tables. I would like to have a generic query for Create Read Update Delete.
The read contains the same "Where" Clause.
Thanks for your help.
Here you have simple example for pure CRUD scenario. Create interface which will contain shared properties for your queries. Implement this interface in all your entity classes. Than create repository. Repository is usually defined as generic but in your case I defined each method as generic so that you can use same repository instence for all entities.
public interface IWellKnownEntity
{
int Type { get; set; }
}
public class Repository
{
public T GetEntityByWellKnownQuery<T>() where T : IWellKnownEntity
{
using (var context = new MyContext())
{
return context.CreateObjectSet<T>().FirstOrDefault(e => e.Type == 1);
}
}
public IEnumerable<T> GetEntitiesByCustomQuery<T>(Expression<Func<T, bool>> where)
{
using (var context = new MyContext())
{
return context.CreateObjectSet<T>().Where(where).ToList();
}
}
public void Create<T>(T entity) where T : IWellKnownEntity
{
using (var context = new MyContext())
{
context.AddObject(entity);
context.SaveChanges();
}
}
public void Update<T>(T entity) where T : IWellKnownEntity
{
using (var context = new MyContext())
{
context.Attach(entity);
context.ObjectStateManager.ChageObjecState(entity, EntityState.Modified);
context.SaveChanges();
}
}
public void Delete<T>(T entity) where T : IWellKnownEntity
{
using (var context = new MyContext())
{
context.Attach(entity);
context.DeleteObject(entity);
context.SaveChanges();
}
}
}
Than you suppose that you have entity product and catebory which impelment well known interface. You can simply call:
var repository = new Repository();
var product = repository.GetEntityByWellKnownQuery<Product>();
product.Name = "Updated";
repository.Update<Product>(product);
var category = repository.GetEntitiesByCustomQuery<Category>(c => c.Id == 1).First();
repository.Delete<Category>(category);
You can futher improve the sample code. This code doesn't use shared context so it is more usable for disconnected scenario (web application). If you use connected scenario like WinForms application or batch application you can implement IDisposable on repository and share context among all methods. Dispose method on repository will hanlde disposing of context. Code for Update and Delete methods will be different because there is no need to attach entity back to context or set entity state.