I have this class
class abstract EntityBase
{
public abstract int Id {get; set; }
}
Now, i change a little bit my linq2sql generated class for user table (set override for Id)
public partial class User: EntityBase, INotifyPropertyChanging, INotifyPropertyChanged
{
...
public override int Id {...}
...
}
Than, i have another template helper class with this function
public static T SingleOrDefault(System.Linq.Expressions.Expression<Func<T, bool>> func)
{
System.Data.Linq.DataContext oDataContext = null;
T retData = GetAll(out oDataContext).SingleOrDefault(func);
if (retData != null)
{
retData.CurrentDataContext = oDataContext;
}
return retData;
}
And i use it like this
Helper<EntityBase>.SingleOrDefault(t => t.Id == 3);
And i get : Class member EntityBase`2.Id is unmapped. The problem is that it is using the Id from EntityBase not from the User class so my question is how can i construct the corresponding lambda expression for this so that it can refer the Id from the user class.
Hope i was clear.
Thanks.
Related
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.
I have two kinds of base classes:
public class Parent { }
public abstract class Child : Parent
{
string ChildKey { get; set; }
}
Derived from Parent, there are many kids:
public class Kid1 : Parent { public string Name { get; set; } }
public class Kid2 : Parent { public long Number { get; set; } }
...
and also many Children as a special group of Childs with extra properties:
public class Child1 : Child { public string Street { get; set; } }
public class Child2 : Child { public long Account { get; set; }}
Now I have two generic repository classes where the "Special One" acts more specific on the extra properties by using an additional filter:
public class Repository<T> : IRepository<T> where T : Parent
{
public IEnumerable<T> GetAll() { return something; }
}
public class ChildRepository<T> : Repository<T>, IChildrenRepository<T> where T : Child
{
public override IEnumerable<T> GetAll() { return base.GetAll().Where(x => x.ChildKey == "y"); }
}
with the interfaces:
public interface IRepository<T> where T : Parent
{ IEnumerable<T> GetAll(); }
public interface IChildRepository<T> : IRepository<T> where T : Child { }
I also need the type safety of the GetAll()-results.
Now I need a generic method to create the desired repository:
IRepository<T> GetRepository() where T : WhatConstraint
{
if (typeof(Child).IsAssignableFrom(T))
return new ChildRepository<T>(); // return 1
return new Repository<T>(); // return 2
}
What is the correct constraint? return 1 needs Child-Constraint (which is wrong for return 2), saying that Type T cannot be used as type parameter in method since there is no implicit reference conversion from T to Child.
The T : Child-constraint is more precise in ChildRepository (and therefore useful, since I can rely on some properties). If I use the same T : Parent-constraint of the Repository, I have to type-check whether T is derived from Child all the times...
Are there any solutions to this?
Okay, here is a detailed solution (which can be written shorter as well as less readable). Since Repository and ChildRepository have conflicting constraints (which is good for the repositories, but bad for GetRepository-factory), I cannot create the ChildRepository using new-keyword. I have to create this object via CreateInstance.
IRepository<T> GetRepository() where T : Parent
{
if (typeof(Child).IsAssignableFrom(T))
{
Type childType = typeof(T); // which is both, Parent and Child
Type classType = typeof(ChildRepository<>);
Type[] typeParams = { childType };
Type repositoryType = classType.MakeGenericType(typeParams);
return Activator.CreateInstance(resultType) as IRepository<T>;
}
return new Repository<T>();
}
Downside of this solution: More complex code analysis, unclear nullability of result, not really intuitive readable (especially existing constraints). But it works.
I am wrapping up a generically-crafted SQL table editor for a configuration application, using Entity Framework, a Repository pattern, so on and so forth. Probably a bit overkill on the layers. In any case, I have a generic MVC controller (we'll call it MyController<T>) looking to send its calls to a generic service layer (MyServices<T>), where everything "of T" is some data model class representing a SQL table, directly. Each and every data model class has an ident field called "Id", that is implemented from a base model (that itself, is implementing an interface).
Everything is very simple and smooth, except when I need to call the FindBy option on a data set, where i have to provide a delegate to search on something of a generic type. I understand that the type constraints need to have an interface attached to it so that I can access that "Id" field in any type T, but doing so causes conflict with any controllers that explicitly implement the generic controller. So:
Generic Service layer:
public abstract class MyServices<T> : IMyService<T> where T : class, new()
{
IMyRepository<T> _MyRepository;
public MyServices(IMyRepository<T> MyRepository)
{
_MyRepository = MyRepository;
}
public IQueryable<T> FindBy(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
{
return _MyRepository.FindBy(predicate);
}
}
Generic Repository:
public partial class MyRepository<T> : IMyRepository<T> where T : class, new()
{
MyTablesEntities _entities = new MyTablesEntities();
public IQueryable<T> FindBy(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
{
IQueryable<T> query = _entities.Set<T>().Where(predicate);
return query;
}
}
Generic Controller:
public class MyController<T> : Controller where T : class, new()
{
private string ViewTitle = typeof(T).ToString();
private readonly IMyServices<T> _MyServices = default(IMyServices<T>);
public MyController() { }
public MyController(IMyServices<T> mtt)
{
_MyServices = mtt;
}
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
T editItem = _MyServices.FindBy(c => **c.Id == id**).SingleOrDefault();
if (editItem == null)
{
return HttpNotFound();
}
return PartialView(editItem);
}
}
and a Controller using MyController:
public class AccountsController : MTTablesController<Accounts>
{ }
Obviously, with this setup, the FindBy delegate clause cannot differentiate the type of T until runtime, so it fails to compile this way, giving:
'T' does not contain a definition for 'Id' and no extension method 'Id' accepting a first argument of type 'T' could be found
If, however, I add the interface (IMyTableEntity) that contains a property of 'Id' to the constraint of the generic controller:
public class MyController<T> : Controller where T : class, MyTables.DataAccess.Metadata.Base.IMyTableEntity, new()
public interface IMyTableEntity
{
int Id { get; set; }
}
I now get THIS error, over on the implementing Controller:
The type 'MyTables.DataAccess.Account' cannot be used as type parameter 'T' in the generic type or method 'MyController<T>'. There is no implicit reference conversion from 'MyTables.DataAccess.Account' to 'MyTables.DataAccess.Metadata.Base.IMyTableEntity'.
I am at an impasse here as both errors lead me back into trying the other way, neither of which are working. I need the generic 'T' on the generic controller to be smart enough to carry the Id field with it, without confusing the implementing controllers above it.
trailmax may have found it...
Your class 'MyTables.DataAccess.Account' must implement IMyTableEntity
My Data modelling is set up in this way:
EF base partial classes:
public partial class Accounts {
public int Id { get; set; }
public string Code { get; set; }
public string Description { get; set; }
}
Metadata models that contain data Annotations:
public class AccountsMetadata : MyTables.DataAccess.Metadata.Base.MyTableEntity {
[Key]
[Required]
[UniqueValidator]
public string Code { get; set; }
[Display(Name="Description")]
[StringLength(100)]
public string Description { get; set; }
}
a bootstrap that ties them together
[MetadataType(typeof(AccountsMetadata))]
public partial class Accounts { }
what i needed to do was add the implementation of the interface to the bootstrap definitions for every partial, i.e.:
[MetadataType(typeof(AccountsMetadata))]
public partial class Accounts : MyTables.DataAccess.Metadata.Base.IMyTableEntity { }
and then follow that up by setting the IMyTableEntity interface as a constraint on T in the Generic Controller, as i outlined above...
I have completely re-written this hoping to make my question clearer. I have chosen the concept of services making use of repositories in my example code.
Example code:
class Program
{
interface IEntity
{
int Id { get; set; }
}
// Example entity could be:
class Book : IEntity
{
public int Id { get; set; }
}
class Magazine : IEntity
{
public int Id { get; set; }
}
interface IRepository<TEntity> where TEntity : class, IEntity
{
IEnumerable<TEntity> GetEntities();
}
interface IBooksRepository : IRepository<Book> { }
interface IMagazineRepository : IRepository<Magazine> { }
class DataStore<TEntity> where TEntity: class, IEntity
{
public IEnumerable<TEntity> GetFromStore()
{
throw new NotImplementedException();
}
}
abstract class RepositoryBase<TEntity> : IRepository<TEntity>
where TEntity : class, IEntity
{
DataStore<TEntity> _dataStore;
public RepositoryBase()
{
_dataStore = new DataStore<TEntity>();
}
public IEnumerable<TEntity> GetEntities()
{
return _dataStore.GetFromStore();
}
}
class BookRepository : RepositoryBase<Book>, IBooksRepository { }
class MagazineRepository : RepositoryBase<Magazine>, IMagazineRepository { }
abstract class ServiceBase<IEntityRepository, TEntity>
where IEntityRepository : IRepository<TEntity>
where TEntity : class, IEntity
{
IEntityRepository _repository;
public ServiceBase(IEntityRepository repository)
{
_repository = repository;
}
public IEnumerable<TEntity> GetEntitiesFromRepository()
{
return new List<TEntity>();
}
}
class BookService : ServiceBase<IBooksRepository, Book>
{
public BookService(IBooksRepository bookRepository)
: base(bookRepository)
{ }
}
class MagazineService : ServiceBase<IMagazineRepository, Magazine>
{
public MagazineService(IMagazineRepository magazineRepository)
: base(magazineRepository)
{ }
}
static void Main(string[] args)
{
var aBookService = new BookService(new BookRepository());
var aMagazineService = new MagazineService(new MagazineRepository());
var books = aBookService.GetEntitiesFromRepository();
var magazines = aMagazineService.GetEntitiesFromRepository();
}
}
This all works fine and perhaps it is valid to ask why I want to change this. Mainly I am just curious if I can make this more neat. It is more a point of curiosity that one of functional correctness I suppose.
Both IBookRepository and IMagazineRepository know which concreate type they represent 'Book' and 'Magazine'
When I define my concreate services: BookService and MagazineService I have to specify the type as well as the interface:
class BookService : ServiceBase<IBooksRepository, Book>{}
class MagazineService : ServiceBase<IMagazineRepository, Magazine>{}
I wondered if I could simplify thier signatures as the Interfaces already know The type I am expecting Book or Magazine.
Can I extract the Entity Type from the inteface such that I no longer need to specify the type when creating concreate service types?
As I pondered this, I discovered a deeper issue with my knowledge of C#:
What exactly is the type of 'thing' that the generic system is looking for between those angle brackets: IEnumerable<TThisThing>.
When I look at intellisense is says T is the type of objects to enumerate.
So as an experiment I grabbed the type of MyType:
Type typeOfMyType = instanceOfMyType.GetType();
IEnumerable<typeOfMyType> enumerable = new List<typeOfMyType>(); //crude example.
Now of course this does not work. So what kind of thing is TThisThing that works between the angle brackets?
is there a way of extracting this information so that I can forgo the
inclusion of 'MyType' in the class definition and use the discovered
TMyType in the example method?
Yes, you simply need to define the generic type parameter in the methods name:
public IEnumerable<TMyType> GetMyTypes<TMyType>()
{
// get list of TMyType instances;
return list;
}
If you don't want to use a generic type parameter at all, you'll have to defer to reflection, and you won't be able to use a compile-time generic type such as returning an IEnumerable<T>.
So what kind of thing is TThisThing that works between the angle
brackets?
TThisThing should be a compile-time known type parameter. When you use Type typeOfMyType = instanceOfMyType.GetType();, the type of instanceOfMyType is only known at run-time.
For example:
var obj = new SomeClass<Foo>();
IEnumerable<Bar> bars = obj.GetMyTypes<Bar>();
Where Foo and Bar:
public class Foo { }
public class Bar { }
I have base class for my entities
public class Entity<T> where T : Entity<T>, new()
{
public XElement ToXElement()
{
}
public static T FromXElement(XElement x)
{
}
}
I have to use this strange construction Entity<T> where T : Entity<T>, because i want static method FromXElement to be strongly-typed
Also, i have some entities, like that
public class Category : Entity<Category>
{
}
public class Collection : Entity<Collection>
{
}
How can i create a generic list of my entities, using base class?
var list = new List<Entity<?>>();
list.Add(new Category());
list.Add(new Collection());
You can't with that definition. There is no "common base class" between Category and Collection (other than object, of course).
If there were, say if Entity<T> were defined as:
public class Entity
{
}
public class Entity<T> : Entity where T : Entity<T>, new()
{
public XElement ToXElement()
{
}
public static T FromXElement(XElement x)
{
}
}
then you could do
var list = new List<Entity>();
list.Add(new Category());
list.Add(new Collection());
But what would that buy you?
Create a marker interface:
public interface IAmAGenericEntity { }
public class Entity<T> where T : IAmAGenericEntity, new()
// ...
public class Category : Entity<T>, IAmAGenericEntity
// ....
var list = new List<IAmAGenericEntity>();
// ...
From the lack of an abstract marker on Entity, I assume that To/FromXElement use reflection and should work for any subtype of Entity. I recommend that you structure your classes as follows:
public class Entity
{
public XElement ToXElement() { ... }
protected static T FromXElement<T>(XElement x)
where T : Entity
{
...
}
}
public class Category : Entity
{
public static Category : FromXElement(XElement x)
{
return FromXElement<Category>(x);
}
}
The "boilerplate" is minimal, and it doesn't require that you creatively circumvent the type system. You don't have to worry about the lack of a common base, or about manual conversions. If you like, you can eliminate the boilerplate entirely and just construct your objects directly from Entity:
public class Entity
{
public XElement ToXElement() { ... }
public static T FromXElement<T>(XElement x)
where T : Entity
{
...
}
}
In essence, what you're doing is implementing a type class, which C# does not directly support. There are a number of ways to work around this lack, but I usually find them to be more trouble than they're worth, especially when it comes to static methods. If C# supported static extension methods, it would be simple, but alas it does not.
You can define a non-generic class to be the base class of all entity classes
public class Entity
{
}
and make Entity inherit Entity
public class Entity<T> : Entity where T : Entity<T>, new()
{
}
Now you can create the list of entities as:
var list = new List<Entity>();
You can solve this problem by adding a non-generic version of the class
class Entity
{
// methods
public T As<T>()
{
if (this is T) return (T)this;
throw new InvalidCastException();
}
}
class Entity<T> : Entity where T : Entity<T>, new()
class Cathegory : Entity<T> {}
and then create the list of the base class:
var list = new List<Entity>()
list.Add(new Cathegory());
Then, if you want to call a "generic specific" operation, you need to call the "As" function or simply cast the object.