it seems if i use an custom class as base of an entity,the ObjectContext.CreateObjectSet will fail with stackoverflow exception
code is:
// This is generated by EF4 and i modify it to my custom class
public partial class EntityA : GClass<EntityA>
{
......
}
public partial class TestEntities : ObjectContext
{
public ObjectSet<EntityA> EntityAs
{
get
{
if ((_EntityAs == null))
{
// here will throw stackoverflow exception
_EntityAs = base.CreateObjectSet<EntityA>("EntityAs");
}
return _EntityAs;
}
}
private ObjectSet<EntityA> _EntityAs;
}
// This is custom class
public partial class EntityA
{
}
// This is my custom base class
public class GClass<T> : EntityObject where T : class
{
public virtual string GetStr()
{
return "GClass";
}
}
I recommend creating an interface for your entity objects instead of changing the base class. Generated code should not be modified.
Update: Due to unexplained downvotes, I'm adding the code below, which spells out precisely what I mean:
// Generated by EF4
public partial class EntityA : EntityObject
{
...
}
// Interface defined in another file
public interface IGClass<T> where T : IGClass<T>
{
string GetStr();
}
// Automatically generated by T4 template
public partial class EntityA : IGClass<EntityA>
{
public virtual string GetStr()
{
return "GClass";
}
}
The resulting code does use CRGP, but does so via an interface instead of a base class.
More info on T4 templates is here.
Related
[Edited for additional clarity]
I have an abstract class where I've defined a property - let's call it 'BulkValueSet'. BulkValueSet is a class which holds a large number of numeric values.
public abstract class Parent
{
public BulkValueSet ValueSet {get;set;}
// additional properties and methods
}
BulkValueSet implements several different interfaces. Let's take two of them called ISpecificValueSetA and ISpecificValueSetB.
public class BulkValueSet : ISpecificValueSetA , ISpecificValueSetB
{
// lots of numbers !
}
Now for the crux of the matter: I have two child classes (ChildA and ChildB) that inherit from the Parent class. I would like for these classes to inherit the BulkValueSet property from the Parent class but modify it via the interfaces defined. I've tried hiding the parent property by using the new keyword
public class ChildA : Parent
{
new public ISpecificValueSetA ValueSet {get;set;}
// additional stuff
}
public class ChildB : Parent
{
new public ISpecificValueSetB ValueSet {get;set;}
// additional stuff
}
the intent being that the property read from the child classes returns the filtered values as provided by the relevant interface. But this isn't really working - Visual studio shows both parent and child properties as being present and accessible and accessing the 'ValueSet' property using the dot operator seems to default to the property defined in the Parent class.
How can I go about this ?
Edit: Adding some additional context - I want to do this with multiple child classes - each with their own interface implementation of BulkValueSet.
what is wrong with it
public abstract class Parent
{
public IBulkValueSet ValueSet {get;set;}
// additional properties and methods
}
update, since the question was changed. Now ISpecificValueSet could be like this
public interface IBulkValueSet : ISpecificValueSetA , ISpecificValueSetB
{
// lots of numbers !
}
public class BulkValueSet : IBulkValueSet
{
// lots of numbers !
}
but it doesn't make much sense to me to inherit a huge class in order to use a part of it.
This is the closest that I think I can get to your desired design:
public interface IParent
{
BulkValueSet ValueSet { get; set; }
}
public abstract class Parent : IParent
{
BulkValueSet IParent.ValueSet { get; set; }
}
public interface ISpecificValueSetA { }
public interface ISpecificValueSetB { }
public interface ISpecificValueSetC { }
public class BulkValueSet : ISpecificValueSetA, ISpecificValueSetB, ISpecificValueSetC { }
public class ChildA : Parent
{
public ISpecificValueSetA ValueSet { get => (this as IParent).ValueSet; }
}
public class ChildB : Parent
{
public ISpecificValueSetB ValueSet { get => (this as IParent).ValueSet; }
}
public class ChildC : Parent
{
public ISpecificValueSetC ValueSet { get => (this as IParent).ValueSet; }
}
I am trying to map reference data entities to dtos, both of which inherit from a generic base class within their own namespace and using an "all purpose" profile to add the mappings. Consider the following code:
namespace Dtos
{
public abstract class ReferenceData<TId>
where TId : Enum
{
public TId Id { get; set; }
public string Description { get; set; }
}
public class ConcreteDto : ReferenceData<MyEnum> { }
}
namespace Entities
{
public abstract class ReferenceData<TId>
where TId : Enum
{
public TId Id { get; set; }
public string Description { get; set; }
}
public class ConcreteEntity : ReferenceData<MyEnum> { }
}
namespace DtoMapping
{
internal abstract class ReferenceDataDtoProfile<TDto, TEntity, TId> : Profile
where TDto : Dtos.ReferenceData<TId>
where TEntity : Entities.ReferenceData<TId>
where TId : Enum
{
public ReferenceDataDtoProfile()
{
}
protected IMappingExpression<TDto, TEntity> CreateDtoToEntityMap()
{
return this.CreateMap<TDto, TEntity>()
.IncludeBase<Dtos.ReferenceData<TId>, Entities.ReferenceData<TId>>();
}
protected IMappingExpression<TEntity, TDto> CreateEntityToDtoMap()
{
return this.CreateMap<TEntity, TDto>()
.IncludeBase<Entities.ReferenceData<TId>, Dtos.ReferenceData<TId>>();
}
protected void CreateMaps()
{
this.CreateDtoToEntityMap();
this.CreateEntityToDtoMap();
}
}
internal sealed class ProfileForConcreteEntity : ReferenceDataDtoProfile<Dtos.ConcreteDto, Entities.ConcreteEntity, MyEnum>
{
public PeriodProfile()
{
this.CreateMaps();
}
}
}
When I run the application and try to get to the endpoint in question I can see in the debugger that the code of the ReferenceDataDtoProfile class gets executed but then I get the exception that there are no mappings for this objects, specifically:
InvalidOperationException: Missing map from
Dtos.ReferenceData'1[MyEnum] to Entities.ReferenceData'1[MyEnum].
Create using CreateMap(ReferenceData'1, ReferenceData'1).
As you can see I am adding the "IncludeBase" method for both ReferenceData abstract classes so I do not understand why I am getting this exception.
On my Web API project I have included the AutoMapper.Extensions.Microsoft.DependendyInjection package version 7.0.0.
Thank you.
It appears that IncludeBase just specifies that the mapping of the derived objects will inherit the configuration of the base objects. However, you still need to create the actual mapping for both the base and derived objects:
protected IMappingExpression<TDto, TEntity> CreateDtoToEntityMap()
{
this.CreateMap<Dtos.ReferenceData<TId>, Entities.ReferenceData<TId>>();
return this.CreateMap<TDto, TEntity>()
.IncludeBase<Dtos.ReferenceData<TId>, Entities.ReferenceData<TId>>();
}
protected IMappingExpression<TEntity, TDto> CreateEntityToDtoMap()
{
this.CreateMap<Entities.ReferenceData<TId>, Dtos.ReferenceData<TId>>();
return this.CreateMap<TEntity, TDto>()
.IncludeBase<Entities.ReferenceData<TId>, Dtos.ReferenceData<TId>>();
}
See Mapping Inheritance for more info.
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);
I have following situation:
using System.Data;
namespace TestClass
{
//this is a class generated by a wsdl and may not be changed
public partial class MyTableClass : DataTable
{
public MyRowClass this[int index]
{
get { return ((MyRowClass) (this.Rows[index])); }
}
public partial class MyRowClass : DataRow
{
protected internal MyRowClass(DataRowBuilder builder)
: base(builder)
{
}
}
}
//in this partial class I am able to extend the wsdl class by my own interfaces
public partial class MyTableClass : IDetailTable
{
IDetailRow IDetailTable.this[int index]
{
get { return this[index]; }
}
public partial class MyRowClass : IDetailRow
{
}
}
public interface IBaseTable
{
IBaseRow this[int index] { get; }
}
public interface IDetailTable : IBaseTable
{
new IDetailRow this[int index] { get; }
}
public interface IBaseRow
{
}
public interface IDetailRow : IBaseRow
{
}
}
The first part is a class generated by a wsdl definition. I have no ability to change anything here.
I have many wsdl definition files, most are very similar. So I want to define common interfaces for all, which will make me handle them easier in my code.
So my idea was to extend them by a partial class definition like above.
But I get an error here, and I have no idea why and what I should do here:
Error 1 'TestClass.MyTableClass' does not implement interface member 'TestClass.IBaseTable.this[int]'. 'TestClass.MyTableClass.this[int]' cannot implement 'TestClass.IBaseTable.this[int]' because it does not have the matching return type of 'TestClass.IBaseRow'. c:\users\mag\documents\visual studio 2012\Projects\TestClass\TestClass\Class1.cs 6 24 TestClass
Only the base interfaces are implemented, not the derived detail interfaces. But why?
C# only supports single-inheritance, i.e., each class can only extend one from one superclass. However, you have MyTableClass extending DataTable in your first partial class, and IDetailTable in the second. That's what's causing the compilation error.
I think what your really trying to get at is that the second partial class should actually extend from the wsdl definition class. So I would change
public partial class MyTableClass : IDetailTable
to
public class MyAwesomeTableClass : MyTableClass
Ok, I have the following structure. Basically a plugin architecture
// assembly 1 - Base Class which contains the contract
public class BaseEntity {
public string MyName() {
// figure out the name of the deriving class
// perhaps via reflection
}
}
// assembly 2 - contains plugins based on the Base Class
public class BlueEntity : BaseEntity {}
public class YellowEntity : BaseEntity {}
public class GreenEntity : BaseEntity {}
// main console app
List<BaseEntity> plugins = Factory.GetMePluginList();
foreach (BaseEntity be in plugins) {
Console.WriteLine(be.MyName);
}
I'd like the statement
be.MyName
to tell me whether the object is BlueEntity, YellowEntity or GreenEntity. The important thing is that the MyName property should be in the base class, because I don't want to reimplement the property in every plugin.
Is this possible in C#?
I think you can do it through GetType:
public class BaseEntity {
public string MyName() {
return this.GetType().Name
}
}
public class BaseEntity {
public string MyName() {
return this.GetType().Name;
}
}
"this" will point to the derived class, so if you were to do:
BaseEntity.MyName
"BaseEntity"
BlueEntitiy.MyName
"BlueEntity"
EDIT: Doh, Gorky beat me to it.
C# implemented a way to look at objects called Reflection. This can return information about the object you are using.
The GetType() function returns the name of the class you are calling it on. You can use it like this:
return MyObject.GetType().Name;
Reflection can do a lot of things. If there is more that you want to know about reflection you can read about it on these websites:
MSDN Reflection Article
Oreilly Chapter
Code Source Tutorial
Change your foreach statement to the following
foreach (BaseEntity be in plugins) {
Console.WriteLine(be.GetType().Name);
}
If you haven't overridden the ToString() method for the class, then you can just write the following
string s = ToString().Split(',')[0]; // to get fully qualified class name... or,
s = s.Substring(s.LastIndexOf(".")+1); // to get just the actual class name itself
using yr code:
// assembly 1 - Base Class which contains the contractpublic class BaseEntity
{
public virtual string MyName // I changed to a property
{
get { return MyFullyQualifiedName.Substring(
MyFullyQualifiedName.LastIndexOf(".")+1); }
}
public virtual string MyFullyQualifiedName // I changed to a property
{
get { return ToString().Split(',')[0]; }
}
}
// assembly 2 - contains plugins based on the Base Class
public class BlueEntity : BaseEntity {}
public class YellowEntity : BaseEntity {}
public class GreenEntity : BaseEntity {}
// main console app
List<BaseEntity> plugins = Factory.GetMePluginList();
foreach (BaseEntity be in plugins)
{ Console.WriteLine(be.MyName);}
Try this pattern
class BaseEntity {
private readonly m_name as string;
public Name { get { return m_name; } }
protected BaseEntity(name as string) {
m_name = name;
}
}
class BlueEntity : BaseEntity {
public BlueEntity() : base(typeof(BlueEntity).Name) {}
}