Entity Framework 5 - only select entities where entity IsActive - c#

Using the Code First approach I have created a number of different entities that inherit from an interface IConcurrent with a property IsActive for example:
public class Currency : IConcurrent
{
public string CurrencyId { get; set; }
public string Description { get; set; }
public bool IsActive { get; set; }
}
Each time I select entities I find myself always having to include a conditional clause such as this real basic example:
db.Currencies.Where(c => c.IsActive);
My question is that is it possible to some how intercept/hook into the DbContext so that my LINQ queries will always return IsActive == true for entities that inherit the IConcurrent interface, to avoid having to explicitly add .Where(c => c.IsActive) each time?
So far I've looked at the possible methods to override in DbContext which none of them seem to fit the bill. Can anyone help?

You can use filtering on the Set<> method to get just active instances, something along the lines of:
public IQueryable<T> GetActive<T>() where T : class, IConcurrent
{
return Set<T>().Where(e => e.IsActive);
}
This method could be included in a class that inherits the DbContext class, or you could make it into an extension method, like:
public static DbContextExtensions
{
public static IQueryable<T> GetActive<T>(this DbContext context)
where T : class, IConcurrent
{
return context.Set<T>().Where(e => e.IsActive);
}
}

Conditional mapping is supported in Model First approach but it is not directly supported in Code first approach. You may have a workaround by creating a property in DBContext similar to the following;
public IQueryable<Currency> ActiveCurrencies
{
get
{
db.Currencies.Where(c => c.IsActive);
}
}

Related

Creating a Generic DbSet.Find() query

I have a database with 3 tables for classes that all implement my IMeetingEntityEntityBaseClass.cs
public class BookingAppDbContext : DbContext
{
public BookingAppDbContext(DbContextOptions<BookingAppDbContext> options) : base(options)
{
}
public DbSet<MeetingSpace> MeetingSpaces { get; set; }
public DbSet<Employee> Employees { get; set; }
public DbSet<Booking> Bookings { get; set; }
}
I started off with only the MeetingSpaces table and was trying to make my database operation methods generic so they could be reused for the other two tables. However they (and my ASP.NET pages) rely on the Id to identify the meeting space. My problem is that I cant figure out how to make the GetById class generic. For the MeetingSpace table query it is as follows:
public MeetingSpace GetById(int id)
{
return db.MeetingSpaces.Find(id);
}
I attempted to use the Find overload with the type specified but the typeof(T) returns 'object', throwing an error that type 'object' cannot be converted to 'T'.
public T GetById<T>(int id) where T : IMeetingEntityBaseClass
{
return db.Find(typeof(T), id);
}
You need to use the DbContext.Set method. Also, you need to add a type constraint since the Set method relies in it (as do all EF entities.) For example:
public T GetById<T>(int id)
where T : class, IMeetingEntityBaseClass
{
return db.Set<T>().Find(id);
}

Using Generic Column with LINQ

I have a base Entity type that I use as a base class for multiple entity types: Customer : Entity, Product : Entity, etc. Each of these has an existing id column named after the entity type: CustomerId, ProductId, etc. Because these all have a different name but the same function, I decided to use an unmapped generic Id column that each of these could define to reference the "real" Id column for that type:
public abstract class Entity<T> where T: Entity<T>
{
[NotMapped]
public abstract int Id { get; set; }
}
public class Customer : Entity<Customer>
{
[JsonIgnore]
public override int Id { get => CustomerId; set => CustomerId = value; }
public int CustomerId { get; set; }
}
The problem is, when I try to use it:
[HttpPut("put")]
public async Task<ActionResult<bool>>> PutEntity(List<T> entities)
{
foreach (T entity in entities)
if (!MyEntities.Any(e => e.Id == entity.Id))
return NotFound(false);
}
I get an exception The LINQ expression 'DbSet<Customer>.Any(d => d.Id == ___Id_0' could not be translated.
Is there any way I can fix this to allow LINQ to run the query with a generic reference to a column with an unknown name?
Try specifying the column name to use for the overridden Id property instead:
public class Customer : Entity<Customer>
{
[Column("CustomerId")]
public override int Id { get; set; }
Another solution is to use configuration classes. You also can create an inheritance hierarchy of these configuration classes so base entity properties are configured in a single place while you can choose to override configuration values as you see fit. Quick example:
public abstract class BaseEntity
{
public int Id { get; set; }
}
public class Customer : BaseEntity
{
// Id not needed
}
public abstract class BaseEntityConfiguration<TEntity>
: IEntityTypeConfiguration<TEntity>
where TEntity is BaseEntity
{
public void Configure(EntityTypeBuilder<TEntity> builder)
{
builder.HasKey(c => c.Id); // defined in single location
}
}
public class CustomerConfiguration : BaseEntityConfiguration<Customer>
{
public void Configure(EntityTypeBuilder<Customer> builder)
{
base.Configure(builder); // configure base class' properties
builder
.Property(c => c.Id)
.HasColumnName("CustomerId"); // override column name
}
}
That sounds like entity framework cannot translate something to sql. Shot in the dark but does this work any better?
[HttpPut("put")]
public async Task<ActionResult<bool>>> PutEntity(List<T> entities)
{
foreach (T entity in entities)
{
int entityId = entity.Id;
if (!MyEntities.Any(e => e.Id == entityId ))
return NotFound(false);
}
}
If you can't compose the Expression where you need it, compose it where you have the pieces.
Since I couldn't find a way to pass the property to the Controller, I added a new property that returns the needed Expression:
public abstract Expression<Func<T, bool>> CompareId { get; }
overrode it in the derived class:
public override Expression<Func<Customer, bool>> CompareId => (e => e.CustomerId == CustomerId);
and substituted it for the whole expression:
T entity;
if (!MyEntities.Any(entity.IsId))
return NotFound(false);
It worked!
Maybe not as clean a solution as I would have liked to come up with, but it allows me to get the expression made, and is still a lot less work than creating identical Controllers for every single entity type.
Probably the biggest caveat here is that I was only able to do this because I was basing the Any on a provided entity. If I had just been provided the Id, I wouldn't have had an existing entity to use to call the property. I guess if I run into a case like that, I'll have to figure that out from there.

Nhibernate - Getting two object type in repository return result

I have two class BookingInfo.cs and BookingTransaction class.
public class BookingInfo
{
public virtual string Code { get; set; }
}
public class BookingTransaction : BookingInfo {
public virtual string CustomerRefNo { get; set; }
}
below is the NHibernate mapping for both classes
public class BookingInfoConfiguration : ClassMap<BookingInfo> {
public BookingInfoConfiguration() {
Table("Bkg_BookingInfo");
LazyLoad();
DynamicUpdate();
Id(x => x.Id).GeneratedBy.GuidComb().UnsavedValue(Guid.Empty);
}
}
public class BookingTransactionConfiguration :
ClassMap<BookingTransaction> {
public BookingTransactionConfiguration() {
Table("Bkg_BookingInfo");
LazyLoad();
DynamicUpdate();
Id(x => x.Id).GeneratedBy.GuidComb().UnsavedValue(Guid.Empty);
}
}
Now i am querying to get rows from database.
CurrentSession.Query<BookingInfo>().ToList();
I get two items for single row in database table. one for Bookinginfo and another for BookingTransaction. but i want to get only result of type Bookinginfo.
How to remove the items of the child class from the result?
As said in Rabban's answer, this is by design. This is called implicit polymorphism. Rabban propose you to change your class hierarchies, but you can instead disable implicit polymorphism if you prefer.
With hbm mappings (I do not use fluent and do not know it), add the attribute polymorphism="explicit" on your class.
Mapping by code supports it too on class mapper with .Polymorphism(PolymorphismType.Explicit).
You can read more about implicit/explicit polymorphism here:
Implicit polymorphism means that instances of the class will be
returned by a query that names any superclass or implemented interface
or the class and that instances of any subclass of the class will be
returned by a query that names the class itself. Explicit polymorphism
means that class instances will be returned only be queries that
explicitly name that class and that queries that name the class will
return only instances of subclasses mapped inside this <class>
declaration as a <subclass> or <joined-subclass>. For most purposes
the default, polymorphism="implicit", is appropriate. Explicit
polymorphism is useful when two different classes are mapped to the
same table (this allows a "lightweight" class that contains a subset
of the table columns).
Its intended that NHibernate returns you both objects. To prevent this behavior create a abstract base class where both other class derive. Then you don't need to duplicate code and you can query each class separately.
Create the base class:
public abstract class BookingBase
{
public virtual string Code { get; set; }
}
and then derive your classes from it:
public class BookingInfo : BookingBase
{
}
public class BookingTransaction : BookingBase
{
public virtual string CustomerRefNo { get; set; }
}
Your mappings and queries can remain the same. And if you want to query both classes with one query, just query BookingBase.

EntityObject to DbContext

I am not sure in terms of exact technical specification for this problem to me but in simple words I am trying to create a wrapper/extension method around to save my entities.
So I added new Entity Data Model (.edmx) file to my project. That generates DbSet(s) like this-
public partial class SUContextContainer : DbContext
{
public SUContextContainer()
: base("name=SUContextContainer")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public DbSet<Category> Categories { get; set; }
public DbSet<Gallery> Galleries { get; set; }
public DbSet<SuperUser> SuperUsers { get; set; }
public DbSet<UserType> UserTypes { get; set; }
}
Now here I am trying to wrap this into an extension method for database operations like (save, delete, update etc..)
I tried creating it as -
public static void Save(this EntityObject objEntity)
{
try // Update Record
{
((IObjectContextAdapter)Global.Context).ObjectContext.ObjectStateManager.ChangeObjectState(objEntity, EntityState.Modified);
Global.Context.SaveChanges();
}
catch (OptimisticConcurrencyException) // Insert Record
{
((IObjectContextAdapter)Global.Context).ObjectContext.ObjectStateManager.ChangeObjectState(objEntity, EntityState.Added);
Global.Context.SaveChanges();
}
}
This method is attached to EntityObject types. Where .edmx code which it generates are of type DbContext.
So Whenever I try to save some entity with this helper method it never finds out.
var galleryEntity = new Gallery {
IsActive = true,
CategoryId = model.CategoryId,
};
galleryEntity.Save(); // the save method is not found.
I tried above method to change in -
public static void Save(this DbSet objEntity)
But this also doesn't seem to take as extension method.
What am I doing wrong.
So Whenever I try to save some entity with this helper method it never
finds out.
It will not, because gallery is just a class and is not inherited from EntityObject.
I don't suggest adding inheritence or modifiying autogenerated classes.
Use power of partial classes:
You can create patial classess for your models with interface.
public partial class Gallery : IEntity
{
//This is your class different than auto generated class by Ef.
}
Also you shouldn't use try catch for decision. That's why you should seperate update and create and make decision on upper level (without try catch).
So your extension methods should be like this.
public static int Update<T>(this T entity) where T : IEntity
{
using(var dbContext=new SUContextContainer())
{
var entry = dbContext.Entry(entity);
dbContext.Set<T>().Attach(entity);
entry.State = EntityState.Modified;
return dbContext.SaveChanges();
}
}
public static int Create<T>(this T entity) where T : IEntity
{
using(var dbContext=new SUContextContainer())
{
dbContext.Set<T>().Add(entity);
return dbContext.SaveChanges();
}
}
Your extension method will only apply to types that inherit from EntityObject.
You will either need to make all of your entity classes inherit from this EntityObject class or create another extension method that applies to the correct type.
Typically when using these kind of persistence patterns you would create an entity base class
public class Entity
{
public int Id { get; set; }
}
and each entity type inherits from it
public class Gallery : Entity
{
public int Name { get; set; }
}
Then you can have common methods that you use across entity types:
public static void Save(this Entity entity);

NHibernate generate mappings from classes?

Is there a way to generate mappings for NHibernate from POCO? This reply to my question makes NHibernate look very interesting. However i have a lot of classes that look like this
public class register_email_job
{
public PK id;
public user_data user;
}
public class user_comment : BaseComment2
{
[IsNullable]
public user_comment parent;
public user_data user;
}
I would like to easily translate this into something compatible with NHibernate. I wouldnbt mind modifying some queries but i prefer not to rewrite each class to use properties and modify class in such a way i need to change how its used everywhere.
-edit- Note that i use inheritance and user_comment has an object to user_comment (thus why it must be nullable. so it doesn't infinitely recurse. null is root).
You may want to take a look at the Auto Mapping abilities of Fluent NHibernate: http://wiki.fluentnhibernate.org/Auto_mapping
In order for NHibernate to construct proxies for your entity classes, you will need to make your non-private members virtual. Public fields will not work with proxy objects, these should be converted to properties.
public class register_email_job
{
public virtual PK id { get; set; }
public virtual user_data user { get; set; }
}
Fluent NHibernate is able to create mapping from classes. It can automap based on conventions, or you can write your own mappers.
Your entities and tables may not match the default conventions, there a several ways to override them.
Using classmap, your mapping might look like this:
public class register_email_job_map : ClassMap<register_email_job>
{
public register_email_job_map()
{
Id( x => x.Id );
References( x=> x.user );
}
}
public class user_comment_map : ClassMap<user_comment>
{
public register_email_job_map()
{
// properties from BaseComment2
References( x=> x.user );
References( x=> x.parent );
}
}

Categories