I am trying to reduce code from the data layer (Class Library) of a project by making a generic DAO class with virtual methods, this way I will have implementations of this class for the various types needed.
For simplicity's sake I will only write the read method for all classes and only the necessary parameters.
One requirement is the object used as return for all methods within this layer, which is a generic class as below:
public class ReturnObject<T>
{
public T Object { get; set; }
}
I started with an interface IDao:
public interface IDao<T>
{
ReturnObject<T> Read(Guid id);
}
And then, the "default implementation":
public abstract class Dao<T> : IDao<T>
{
// Database context.
protected Context Context { get; } = new Context();
public virtual ReturnObject<T> Read(Guid id)
{
// Creating return object.
var returnObject = new ReturnObject<dynamic>();
// Reading entity from database.
try
{
switch (typeof(T).ToString())
{
case "Foo":
returnObject.Object = Context.Foos.First(o => o.Id == id) as dynamic;
break;
case "Bar":
returnObject.Object = Context.Bars.First(o => o.Id == id) as dynamic;
break;
}
}
catch (Exception exception)
{
...
}
finally
{
...
}
// Returning result.
return returnObject as ReturnObject<T>;
}
}
So, basically this is the code reduction I'm trying to get. Based on the T class type I will be able to switch the proper set from the context, store the read object into the returnObject and then send it back to the caller.
For organization and other reasons, I also have several inherited classes, like this:
public class DaoFoo : Dao<Foo>
{
}
And finally, my problem. I'm positive I'm misinterpreting some concepts here and that's why I'm getting null values when calling the method read as exampled below:
public class FooController : ApiController
{
public IHttpActionResult Get(Guid id)
{
var foo= new DaoFoo().Read(id);
return Content(HttpStatusCode.OK, new foo.Object);
}
}
When debugging I can see that the Dao class is sending the right object, with all its parameters, like in the image:
However, the calling method always gets null, like in the image:
With all that said, can someone point out what I'm doing wrong here?
Thanks in advance!
You cast dynamic as ReturnObject which results in null, because it cannot cast one type to another.
Try not using dynamic, your method is generic so use T instead, so you dont have to cast
returnObject is a ReturnObject<object>, but returnObject as ReturnObject<T> is null. The as operator will return null if the provided value isn't of the specified type.
Related
I have a casting issue and I was wondering if anyone would be able to help me see how I can fix this issue?
Basically I'm trying to create a CSV generator console program that will take a list of machine records from the DB and put them into a CSV.
The code below is simplified but generally similar to my implementation currently:
public interface IRecord
{
}
public class MachineRecord : IRecord
{
string Name {get;set;}
string ErrorCount {get;set;}
}
public interface IRecordStore
{
string GenerateRecord(IRecord record);
}
public class CSVMachineRecordStore : IRecordStore
{
public string GenerateRecord(IRecord record)
{
var machineRecord = (MachineRecord)record;
var strBuilder = new StringBuilder();
strBuilder.Append(machineRecord.Name);
strBuilder.Append(machineRecord.ErrorCount);
return strBuilder.ToString();
}
}
So basically here I've created a class that inherits from IRecordStore, and in our case we have to create an implementation of GenerateRecord. The problem here is I have to cast the record of be of type MachineRecord or the compiler will throw a casting error out, this is due to Record not having any properties set.
Is it possible to not have the direct cast in this implementation so this line of code will be like:
public class CSVMachineRecordStore : IRecordStore
{
public string GenerateRecord(IRecord record)
{
var machineRecord = record; //we want to remove the explicit cast
var strBuilder = new StringBuilder();
strBuilder.Append(machineRecord.Name);
strBuilder.Append(machineRecord.ErrorCount);
return strBuilder.ToString();
}
}
I know I can fix this issue by adding Name and ErrorCount properties to IRecord, but IRecord is a very generic interface that can have anything.
We want to be able to create a CSV program that can handle machine records, customer records, employee records, supplier records, etc...
I'm thinking of using generics, and I've played with them a bit but I've had some trouble getting it to work too.
Use generics:
public interface IRecordStore<T> where T:IRecord
{
string GenerateRecord(T record);
}
Then implement:
public class CSVMachineRecordStore : IRecordStore<MachineRecord>
{
public string GenerateRecord(MachineRecord record)
{
var machineRecord = record; //we want to remove the explicit cast
var strBuilder = new StringBuilder();
strBuilder.Append(machineRecord.Name);
strBuilder.Append(machineRecord.ErrorCount);
return strBuilder.ToString();
}
}
I wrote this in a hurry, make sure to check for silly errors.
The type casting exception occurs when the IRecord instance is not an instance of MachineRecord.
To answer your question how to fix the casting issue, you should have a look at the as operator.
However, for me this looks like making the IRecordStore interface generic could help you prevent the type issues you're experiencing:
[Edit] I noticed since IRecordStore is an interface you could even make the generic type contravariant. This allows you to assign a variable
of type IRecordStore<IRecord> with an instance of IRecordStore<MachineRecord> or more explicitly CSVMachineRecordStore.
public interface IRecordStore<in T> where T : IRecord
{
string GenerateRecord(T record);
}
public class CSVMachineRecordStore : IRecordStore<MachineRecord>
{
public string GenerateRecord(MachineRecord record)
{
var machineRecord = record;
var strBuilder = new StringBuilder();
strBuilder.Append(machineRecord.Name);
strBuilder.Append(machineRecord.ErrorCount);
return strBuilder.ToString();
}
}
I am trying to create a Generic interface where the parameter type of one of the methods is defined by the generic
EDIT
I've changed the question slightly after realising I have probably confused matters by specifying a type parameter in the Factory creation method. What I have is two types of API calls that I need to make to a 3rd party API. The first retrieves a record from the API using an Id that is an int. The second also retrieves a record from the API but the Id is a string (guid). I have a class for each record type (ClientEntity and InvoiceEntity) that both implement a Generic Interface where I pass in the Id type
This is the Interface in which I declare a Method with an id Parameter
public interface IGeneric<TId>
{
void ProcessEntity(TId id);
}
I implement the interface in a couple of classes, one sets the id to be an int, the other a string.
public class ClientEntity: IGeneric<int> // Record with Id that is an int
{
public void ProcessEntity(int id)
{
Console.WriteLine(id);
// call 3rd party API with int Id
}
}
public class InvoiceEntity: IGeneric<string> // Record with Id that is a string (guid)
{
public void ProcessEntity(string id)
{
Console.WriteLine(id);
// call 3rd party API with string Id
}
}
What I would like to know is how do I use this within a factory pattern?
public static class GenericFactory
{
public static IGeneric<WhatGoesHere> CreateGeneric(string recordType)
{
if (recordType == "Client")
{
return new ClientEntity();
}
if (type == "Invoice")
{
return new InvoiceEntity();
}
return null;
}
}
The objective is to use the factory to instantiate the correct class so that I can call the ProcessEntity method
EDIT
I don't want to have to pass in the Generic type to the factory method because the class that is created by the factory should handle that. When I create the object, I don't know what Id type is required, I want the factory to handle that
e.g.
var myGeneric = GenericFactory.CreateGeneric("Client");
myGeneric.ProcessEntity("guid")
or
var myGeneric = GenericFactory.CreateGeneric("Invoice");
myGeneric.ProcessEntity(1234)
I hope that makes sense
You should be able to do something like this:
public static class GenericFactory
{
public static IGeneric<T> CreateGeneric<T>()
{
if (typeof(T) == typeof(string))
{
return (IGeneric<T>) new GenericString();
}
if (typeof(T) == typeof(int))
{
return (IGeneric<T>) new GenericInt();
}
throw new InvalidOperationException();
}
}
You would use it like this:
var a = GenericFactory.CreateGeneric<string>();
var b = GenericFactory.CreateGeneric<int>();
Note that this uses a strongly-typed call rather than passing in the type name as a string (which may or may not be what you actually want).
If instead you want to pass a string for the type name, you will have to return an object because there is no way to return the actual type:
public static object CreateGeneric(string type)
{
switch (type)
{
case "string": return new GenericString();
case "int": return new GenericInt();
default: throw new InvalidOperationException("Invalid type specified.");
}
}
Obviously if you have an object you would normally have to cast it to the right type in order to use it (which requires that you know the actual type).
Alternatively, you could use reflection to determine what methods it contains, and call them that way. But then you'd still need to know the type in order to pass a parameter of the right type.
I think that what you are attempting to do here is not the right approach, which you will discover once you start trying to use it.
Hacky solution: Use dynamic
Nevertheless, there is one way you can get something close to what you want: Use dynamic as follows (assuming that you are using the object CreateGeneric(string type) factory method from above):
dynamic a = GenericFactory.CreateGeneric("string");
dynamic b = GenericFactory.CreateGeneric("int");
a.ProcessEntity("A string");
b.ProcessEntity(12345);
Be aware that dynamic uses reflection and code generation behind the scenes, which can make the initial calls relatively slow.
Also be aware that if you pass the wrong type to a method accessed via dynamic, you'll get a nasty runtime exception:
dynamic a = GenericFactory.CreateGeneric("string");
a.ProcessEntity(12345); // Wrong parameter type!
If you run that code, you get this kind of runtime exception:
Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: The best overloaded method match for 'ConsoleApplication1.GenericString.ProcessEntity(string)' has some invalid arguments
at CallSite.Target(Closure , CallSite , Object , Int32 )
at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid2[T0,T1](CallSite site, T0 arg0, T1 arg1)
at ConsoleApplication1.Program.Main() in D:\Test\CS6\ConsoleApplication1\Program.cs:line 71
Usually for that Factory using some DI container (DI can be useful, for example, when GenericInt or GenericString has dependencies), but to demonstrate just Idea how you can resolve this:
void Main()
{
GenericFactory.CreateGeneric<int>();
GenericFactory.CreateGeneric<string>();
}
public static class GenericFactory
{
private static Dictionary<Type, Type> registeredTypes = new Dictionary<System.Type, System.Type>();
static GenericFactory()
{
registeredTypes.Add(typeof(int), typeof(GenericInt));
registeredTypes.Add(typeof(string), typeof(GenericString));
}
public static IGeneric<T> CreateGeneric<T>()
{
var t = typeof(T);
if (registeredTypes.ContainsKey(t) == false) throw new NotSupportedException();
var typeToCreate = registeredTypes[t];
return Activator.CreateInstance(typeToCreate, true) as IGeneric<T>;
}
}
public interface IGeneric<TId>
{
TId Id { get; set; }
void ProcessEntity(TId id);
}
public class GenericInt : IGeneric<int>
{
public int Id { get; set; }
public void ProcessEntity(int id)
{
Console.WriteLine(id);
}
}
public class GenericString : IGeneric<string>
{
public string Id { get; set; }
public void ProcessEntity(string id)
{
Console.WriteLine(id);
}
}
The answer marked correct is fine if you want to use Static class but but what if you
want to return an DI injected type instead of newing an object? I suggest the
following!
public interface IGenericFactory
{
IGeneric<T> GetGeneric<T>() where T : class;
}
public class GenericFactory: IGenericFactory
{
private readonly IGeneric<int> intGeneric;
private readonly IGeneric<string> stringGeneric;
public GenericFactory(IGeneric<int> intG, IGeneric<string> stringG)
{
intGeneric = intG;
stringG = stringG;
}
public IGeneric<T> GetGeneric<T>() where T : class
{
if (typeof(T) == typeof(IGeneric<int>))
return (IGeneric<T>)Convert.ChangeType(intGeneric, typeof(IGeneric<T>));
if (typeof(T) == typeof(IGeneric<string>))
return (IGeneric<T>)Convert.ChangeType(stringGeneric,typeof(IGeneric<T>));
else
throw new NotSupportedException();
}
}
Please note i simply injected the two expected return types for clarity in the constructor. I could have implemented the factory as a Dictionary and injected the return objects into this Dictionary. Hope it helps.
I'm thinking you don't want to have to enter the type parameter similar to the LINQ methods. However the magic behind that happens because the type parameter is used in the normal parameter definitions. For example in the ToList<string>() method you can see that TSource is used between the parenthesis.
public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source);
That's how the compiler knows that you want a List<string> if you call ToList() instead of ToList<string>() when called from an IEnumerable<string>
However, I don't think you need a generic type parameter in your factory method at all. All you have to do is create a non-generic version of your TGeneric<TId>
public interface IGeneric { }
public interface IGeneric<TId> : IGeneric
{
void ProcessEntity(TId id);
}
And remove the <WhatGoesHere> from the CreateGeneric method:
public static IGeneric CreateGeneric(string recordType)
{
if (recordType == "Client")
{
return new ClientEntity();
}
if (recordType == "Invoice")
{
return new InvoiceEntity();
}
return null;
}
If the function does not know the type, make it generic.
If the children are generics of different types (<int>, <string>), return object and cast inside the same factory class (Factory<T>), It is safe by typeof.
Personally, I prefer to specify the type with generics, without using an additional parameter, eg a string.
public class Program
{
public static void Main(string[] args)
{
List<Number> something = new();
Do(something);
}
public static void Do<T>(List<T> list)
{
list.Add(Factory<T>.Create());
}
}
public abstract class Factory<T>
{
private static Object ConcreteF()
{
if (typeof(T) == typeof(Number))
return new ChildGenericNumber();
throw new Exception("");
}
public static T Create()
{
return (Factory<T>)ConcreteF()).Build();
}
protected abstract T Build();
}
I have a situation in which I would like to instantiate a type that implements a generic interface, depending on the value of an enum passed to a factory method. However, I'm having problems with the return type of the factory method. I've created a short, complete program below which demonstrates what I'm trying to do:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CreateGenericTypeFactory
{
class Program
{
static void Main(string[] args)
{
var request = new Request { RequestType = RequestType.A };
var processor = ProcessorFactory.Create(request.RequestType);
var result = processor.Process();
}
}
public class ProcessorFactory
{
// This obviously doesn't work, as I don't know the
// result type upfront.
public static IRequestProcessor<TResult> Create<TResult>(RequestType requestType)
{
switch (requestType)
{
case RequestType.A:
return new RequestProcessorA();
case RequestType.B:
return new RequestProcessorB();
default:
throw new InvalidOperationException();
}
}
}
public interface IRequestProcessor<TResult>
{
TResult Process();
}
public class RequestProcessorA : IRequestProcessor<ResultA>
{
public ResultA Process() { throw new NotImplementedException(); }
}
public class RequestProcessorB : IRequestProcessor<ResultB>
{
public ResultB Process() { throw new NotImplementedException(); }
}
public class ResultA { }
public class ResultB { }
public enum RequestType { A, B }
public class Request
{
public RequestType RequestType { get; set; }
// Other properties
}
}
As you can see, the implementations of IRequestProcessor<TResult> differ only by the type of result Process() returns. In reality, those results are quite different, but the overall steps to both process, and return, the data should ideally be the same.
I contemplated the idea of mapping the enum values to the result types in a dictionary, then using that map to select, and construct, a result type, passing that to the factory instead, as it would then be able to infer the type, but I was wondering if there was a cleaner way.
Can any of you shed some light on a potential solution?
First Option
You can change the declaration of TResult in IRequestProcessor as covariant. If you do so you've the ability to return a derived type as base type.
This will look like that:
public interface IRequestProcessor<out TResult>
{
TResult Process();
}
The out declaration of TRequest is the key.
Having this you need a base type that ALL result types derive. I created a marker interface and all results implement it:
public interface IResult { }
public class ResultA : IResult { }
public class ResultB : IResult { }
Now you're able to handle all results as IResult. You could change the signature of ProcessorFactory.Create:
public static IRequestProcessor<IResult> Create(RequestType requestType)
{
switch (requestType)
{
case RequestType.A:
return new RequestProcessorA();
case RequestType.B:
return new RequestProcessorB();
default:
throw new InvalidOperationException();
}
}
Now your code in Main() will compile and run as expected except the fact that you receive IResult instead of the special type.
That's the best you can do to handle all the common stuff. When it comes to the special cases you've to cast the result instance to the special type. You can't use generics to do that.
Second option
Another way meight be to create a generic method that contains the code of your Main() that knows the special type as generic parameter. In that case you can change the signature of ProcessorFactory.Create to the following and you've to cast all return values:
public static IRequestProcessor<TResult> Create<TResult>(RequestType requestType)
{
switch (requestType)
{
case RequestType.A:
return (IRequestProcessor<TResult>)new RequestProcessorA();
case RequestType.B:
return (IRequestProcessor<TResult>)new RequestProcessorB();
default:
throw new InvalidOperationException();
}
}
You don't need the marker interface of first option in that case.
The cast will work because you create the correct request processor.
This returns correctly casted code but you need to move your Main-Code to a generic method or you specify the generic directly which makes RequestType obsolete.
if we take your line of code that calls the process function and not use the var and try to solve it the will have a problem.
(ResultA|ResultB) result = processor.Process();
witch one will it be.. if we cant solve it.. we cant expect the compiler to solve it for us.. so.. what solutions we have..
Hard coded one
Split the definitions into separate (compatible) types, this is the worst as it will make you double the code and have switches all over the place.
ResultA resultA = processorA.ProcessA();
ResultB resultB = processorB.ProcessB();
Remove ambiguity
Make your processor class return always the same type, unifying the return type with an interface, and removing the generics
public interface IResult { }
public class ResultA : IResult { }
public class ResultB : IResult { }
public interface IRequestProcessor //no longer needs generic
{
IResult Process();
}
IResult result = processor.Process();
Go basic
if you really need the generics, and|or cant unify the code with interfaces.. just go the only thing you can count on.. everything is an object.. and ignore types whenever you have a conflict..
Object result = processor.Process();
personally I would go with solution 2.. single interfaces, because.. it's for this kind of situations they exist..
PS: Try to stop using var, is may be easier to write, but is harder to think ;)
I'm trying to figure out how I can make a Generics call take a variable for the Type. In the call below it take a type "DAL.Account" and works fine.
var tst = ctx.GetTable<DAL.Account>().Where(t => t.Sbank == "000134");
I want to change that so that I can pass a variable in place of the "DAL.Account". Something like this but I know that won't work as you can't pass property as a Type.
ctx.GetTable<Criteria.EntityType>().Where(LinqToSQLHelper.BuildWhereStatement(Criteria.StateBag), Criteria.StateBag.Values.ToArray())
Below is the shell pieces of code I think explains what I'm trying to do. Generics is not my strong suit so I'm looking for some help. Is there anyway that I can make this happen?
//Stores a "Type" that indicates what Object is a Criteria for.
public class AccountCriteria : IGeneratedCriteria
{
...
public Type EntityType
{
get {return typeof(DAL.Account);}
}
}
//I have added a function to the DataContext called "GetTable"
// And then used it as an example in a Console App to test its functionality.
public class ADRPDataContext : NHibernateDataContext
{
...
public CodeSmith.Data.NHibernate.ITable<T> GetTable<T>() where T : EntityBase
{
var tb = new CodeSmith.Data.NHibernate.Table<T>(this);
return tb;
}
}
// console application that uses DataContext.GetTable
class Program
{
static void Main(string[] args)
{
using (var ctx = new ADRPDataContext())
{
var tst = ctx.GetTable<DAL.Account>().Where(t => t.Sbank == "000134");
}
}
}
//ExistsCommand class that uses the EntityType property of the Critera to generate the data.
public class ExistsCommand
{
private IGeneratedCriteria Criteria { get; set; }
protected override void DataPortal_Execute()
{
using (var ctx = new DC.ADRPDataContext())
{
//This was my first attempt but doesn't work becuase you can't pass a property in for a Type.
//But I can figure out how to write this so that it will work.
Result = ctx.GetTable<Criteria.EntityType>().Where(LinqToSQLHelper.BuildWhereStatement(Criteria.StateBag), Criteria.StateBag.Values.ToArray()).Count() > 0;
}
}
}
You are looking to instantiate a generic type. Some info can be found here
This is a simple example demonstrating how to instantiate a List with a capacity of 3. Here is a method that you can call to create a generic when you don't know the type:
public static Object CreateGenericListOfType(Type typeGenericWillBe)
{
//alternative to the followin:
//List<String> myList = new List<String>(3);
//build parameters for the generic's constructor (obviously this code wouldn't work if you had different constructors for each potential type)
object[] constructorArgs = new Object[1];
constructorArgs[0] = 3;
//instantiate the generic. Same as calling the one line example (commented out) above. Results in a List<String> with 3 list items
Type genericListType = typeof(List<>);
Type[] typeArgs = { typeGenericWillBe };
Type myNewGeneric = genericListType.MakeGenericType(typeArgs);
object GenericOfType = Activator.CreateInstance(myNewGeneric, constructorArgs);
return GenericOfType;
}
And here is some sample code that will show you the example method works:
List<String> Strings = (List<String>)InstantiateGenericTypeWithReflection.CreateGenericListOfType(typeof(String));
//demonstrate the object is actually a List<String> and we can do stuff like use linq extensions (isn't a good use of linq but serves as example)
Strings.Add("frist");
Strings.Add("2nd");
Strings.Add("tird");
Console.WriteLine("item index 2 value: " + Strings.Where(strings => strings == "2").First());
In your example, replace your GetTable<Criteria.EntityType>() with CreateGenericTableOfType(Criteria.EntityType). This will return a generic table of whatever type you pass in. You will of course need to implement the method properly (handle constructor args, change List to Table etc).
I think you need to change the way you're doing this slightly, and instead use generics instead of the EntityType property. Perhaps something along the lines of the following:
// Create an abstract class to be used as the base for classes that are supported by
// ExistsCommand and any other classes where you need a similar pattern
public abstract class ExtendedCriteria<T> : IGeneratedCriteria
{
public ExistsCommand GetExistsCommand()
{
return new ExistsCommand<T>(this);
}
}
// Make the non-generic ExistsCommand abstract
public abstract class ExistsCommand
{
protected abstract void DataPortal_Execute();
}
// Create a generic sub-class of ExistsCommand with the type parameter used in the GetTable call
// where you were previously trying to use the EntityType property
public class ExistsCommand<T> : ExistsCommand
{
protected override void DataPortal_Execute()
{
using (var ctx = new DC.ADRPDataContext())
{
Result = ctx.GetTable<T>().Where(LinqToSQLHelper.BuildWhereStatement(Criteria.StateBag), Criteria.StateBag.Values.ToArray()).Count() > 0;
}
}
}
// Derive the AccountCriteria from ExtendedCriteria<T> with T the entity type
public class AccountCriteria : ExtendedCriteria<DAL.Account>
{
...
}
I would like find a workaround to accomplish a simple solution in order to automatize certain operation through EF.
What I need it's takeover during saving and retrieving process to modifying query result, but this class will be able to make that work for any type entities.
Example: I have a MyTestDb. So in my C# project I create a new entity model (MyTEstDbModel.edmx), with relative POCO class generation.
Well, a point of interest could be implementing a new custom class like following:
class Example
{
private ObjectContext _context;
private Example(ObjectContext obj) { _context = obj; }
public void Store(ObjectSet<???generic???> os)
{
// problem here: I dont't know the type contained in ObjectSet
// but if I Knew its type, I could make a work like this:
// -> foreach every instance in objectSet to check if exist some property
// via reflection, if i found them, then I set always the same values.
// Why this? Because all my db contains some common filed
// like (createdByUser, TimeToUpdate, and so on..), so it wold be boring
// setting all those fileds from any point of program.
}
public void Retrive(ObjectSet<???generic???> os)
{
// here problem too: all my queries will be filtered by one or more value
// fileds, but I cannot use lambaExpression cos I don't Know the type
// contained in objectSet<..>
}
//....
finally, by any point of program, the code should appear like following:
Example obj = new Example(myEntityContext); //-> global
var result = myEntityContext.ObjectSetTyped.Where(..lambaExpression..condition)
result.someProperty = "...";
obj.Store(result); // store method will fill all other boring filed automatically.
Can anyone give me some tips, help, suggestion about my issue?
Thanks in advance...
Update
Now, just only another problem. I'd to filter my ObjectSet through retrieve method like following:
public void Retrieve<TEntity>(IQueryable<TEntity> ooo) where TEntity : IC
{
ooo = ooo.Where(p => p.Filed == "MyDefaultValue");
}
But, from external method, not objectSet result is affect by my filter.
How so..?
MyEntities ent = new...
MyWrapper wrap = new MyWrapper();
wrap.Retrieve(ent.Users);
//problem here -> users objectSet is always the same..
Define interfaces which will allow you to do this. For example:
public interface IEntity
{
DateTime CreatedAt { get; set; }
string CreatedBy { get; set; }
}
You need to "implement" this interface in your entities. You can for example either modify T4 template generating entities or implement it in partial class. Both properties must be already defined in the model so the implementation is only declarative:
public partial class MyEntity : IEntity // That's all
{ }
Now you can define Store like:
public void Store<TEntity>(TEntity entity) where TEntity : IEntity
{
...
}
Same can be done with query but you can for example define custom extension method:
public static IQueryable<TEntity> GetUserEntities(this IQueryable<TEntity> query, string user)
where TEntity : IEntity
{
return query.Where(e => e.CreatedBy == user);
}
You will simply define your query like:
var result = myEntityContext.MyEntities.GetUserEntities("someName");
Other approach is defining simply GetQuery on your custom context:
public IQueryable<T> GetQuery<T>() where T : IEntity
{
var query = GetObjectSetSomehow;
return query.ApplyGlobalConditions(); // Just another extension with your conditions
}
I'm not a big fan of the repository pattern but generally what you are trying to do is close to generic repository so check for example this post. It is just some example which can be further extended.
yeah, I just want a generic approach, likewise I realized with dataset and datatable.. but it seems impossible to achieve..
..ehmm..however, let me show yuo following code snippet, dynamic keyword looks like something to hopeful.... maybe I'm colse to solution..?
public ObjectSet<dynamic> Retrieve(string entity, string context)
{
Type myObjectContextType = Type.GetType(context);
ConstructorInfo cs = myObjectContextType .GetConstructor(new Type[] { });
dynamic myObjContext = cs.Invoke(new object[] { });
Type t = Type.GetType(entity);
ConstructorInfo xi = t.GetConstructor(new Type[] { });
dynamic UserEntity = xi.Invoke(new object[] { });
!problem here!
ObjectSet<?????> os = myObjContext.UserEntity.Where(...)
return ...
}
I'm very surprised..EF is a great instruments to develope more efficiently ways but too little "generalizalbe"