I've been struggling a bit with this tiny problem - and I'm quite sure there's an "easy" solution.
I have a generic nHibernate base-repository class with the following method:
public IList<T> GetAll()
{
using (var session = SessionProvider.OpenSession())
{
return session.Query<T>().ToList();
}
}
However - I'm trying to control my model by using some very simple interfaces. I have an interface - ISetDeleted:
public interface ISetDeleted
{
bool Deleted { get; set; }
}
In my GetAll()-method I would like to check it the current type implements this interface - and if it does, only return the entities that are not marked as deleted:
public IList<T> GetAll()
{
using (var session = SessionProvider.OpenSession())
{
if (typeof(T) is ISetDeleted)
{
// Only retrieve entities that are not marked as deleted
// WHAT DO I DO HERE?
}
return session.Query<T>().ToList();
}
}
I know I could just retrieve all the entities and loop through these - but I would prefer a cleaner approach - e.g. an expression that implements the check (if possible).
It would be very much appreciated if someone could help me out with this :)
First
typeof(T) is ISetDeleted
will only return true if the type parameter is ISetDeleted, not if it implements the interface. You probably want
if (typeof(ISetDeleted).IsAssignableFrom(typeof(T)))
Second, I think you want
return session.Query<T>().Where(x => !((ISetDeleted)x).IsDeleted).ToList();
You can use Linq (namespace System.Linq):
public IList<T> GetAll()
{
using (var session = SessionProvider.OpenSession())
{
if (typeof(ISetDeleted).IsAssignableFrom(typeof(T)))
{
return session.Query<T>().Where(o => !(ISetDeleted) o).Deleted).ToList();
}
else
{
return session.Query<T>().ToList();
}
}
}
If you can write it like this, it will be easier to extend in future and also allow you to add additional constraints:
public IList<T> GetAll()
{
using (var session = SessionProvider.OpenSession())
{
var query = session.Query<T>();
if (typeof(ISetDeleted).IsAssignableFrom(typeof(T)))
{
query = query.Where(x => !(ISetDeleted)x).Deleted);
}
return query.ToList();
}
}
which should work provided that session.Query returns an IQueryable
Related
I have a custom collection type ObservableStateCollection that, for simplistic purposes, looks like:
public class ObservableStateCollection<T> : IList<T>, INotifyCollectionChanged, INotifyPropertyChanged where T : StateObservable
{
private List<T> _items;
private List<T> _deleted;
public IEnumerator<T> GetEnumerator()
{
return _items.GetEnumerator();
}
public IEnumerable<StateObservable> GetAll()
{
return _items.Concat(_deleted);
}
//...
}
Note that type T must be derived from StateObservable.
Now, I'm neck deep in reflection. I'll spare the details of 'why', and just show you where I'm currently at. I need to check if a particular property on my model is an ObservableStateCollection<T> and use a foreach to loop through the GetAll() method.
Currently, I'm at:
if(prop.PropertyType.GetGenericTypeDefinition() == typeof(ObservableStateCollection<>))
{
var collection = (ObservableStateCollection<StateObservable>)prop.GetValue(model, null);
foreach (var e in collection.GetAll())
{
//act on ObservableStateCollection<StateObservable>
}
}
which throws an exception on the line var collection = ..., as I can't cast ObservableStateCollection<DerivedType> to ObservableStateCollection<BaseType>
What are my options here? How to I get a strongly typed object back that I can call GetAll on?
ahh got it. I invoked GetAll via reflection. Not sure why that didn't occur to me at first:
if(prop.PropertyType.GetGenericTypeDefinition() == typeof(ObservableStateCollection<>))
{
MethodInfo m = prop.PropertyType.GetMethod("GetAll");
var collection = m.Invoke(prop.GetValue(model, null), null);
foreach (var e in (IEnumerable)collection)
{
\\act on item in collection
}
}
If have following classen
public interface ISomething { int Id { get; set; } }
public class SomethingA : ISomething {...}
public class SomethingB : ISomething {...}
In another class I have following two lists:
List<SomethingA> aValues;
List<SomethingB> bValues;
My question is if there is a possibility to do something like this:
public List<ISomething> GetList(bool select) {
return select ? aValues : bValues;
}
My goal is to use this as this:
GetList(true).Single(x => x.Id) // or
foreach (var value in GetList(false))
{
value.Id = 18;
}
// anything else
UPDATE:
I see, there are good possibilities. But is there also a way to also achieve the following?
GetList(true).Remove(myValue);
You can't return List<ISomething> because List<T> is not covariant and classes can't be. IEnumerable<T> is covariant, you may use it as readonly sequence.
Change the method to return IEnumerable<ISomething>
public static IEnumerable<ISomething> GetList(bool select)
{
return select ? (IEnumerable<ISomething>)aValues :bValues;
}
Then do
var result = GetList(true).Single(x => x.Id == 0);
foreach (var value in GetList(false))
{
value.Id = 18;
}
As for your update: If you like to remove the item you need to lose some flexibility. I.e Use non generic IList as the return type.
public static IList GetList(bool select)
{
return select ? (IList)aValues : bValues;
}
Then do
IList list = GetList(true);
foreach (var value in list.OfType<ISomething>())//OfType or Cast can be used
{
if (value.Id == 6)//Whatever condition
{
list.Remove(value);
break;
}
}
I like the OfType extension because it returns the typed list you need
var listA = initialList.OfType<TypeA>(); //return List<TypeA>
var listB = initialList.OfType<TypeB>(); //return List<TypeB>
So in your case you start with
var aValues = List<ISomething>.OfType<SomethingA>()
and then you can iterate on whichever subcollection you need. Of course you are then working with a IEnumerable, but that can be converted implicitly back to a IEnumerable<ITest>.
If you want to filter out values, I would create explicit methods to remove them but it depends on what you need to achieve in the end (for example comparing on a Id instead of the whole object):
public IEnumerable<T> Remove<T>(this List<IDisposable> values, T valueToRemove) where T: IComparable
{
return values.OfType<T>().Where(t => valueToRemove.CompareTo(t) != 0);
}
The simplest solution may be using Linq Cast() like this:
public List<ISomething> GetList(bool select)
{
return (List<ISomething>)(#select ? aValues.Cast<ISomething>() : bValues.Cast<ISomething>());
}
I see, there are good possibilities. But is there also a way to also achieve the following?
GetList(true).Remove(myValue);
To remove from the original lists, you are likely best of with a specialized Remove method on the class in question as others have suggested, as most solutions here return a copy of the original list.
You may remove the element from a copy of the list quite easily like so, but I understand that's not what you are asking.
var result = GetList(true);
result.Remove(myValue);
You can either use the .Cast<T> method like this:
if (select)
{
return aValues.Cast<ISomething>().ToList();
}
else
{
return bValues.Cast<ISomething>().ToList();
}
or add all items to a commong Lis() like this:
var ret = new List<ISomething>();
if (select)
{
ret.AddRange(aValues);
}
else
{
ret.AddRange(bValues);
}
return ret;
Since you only want to iterate it, I would write the method like this:
public IEnumerable<ISomething> GetList(bool select) {
return select ? aValues.Cast<ISomething>() : bValues.Cast<ISomething>();
}
You can also look at this StackOverflow question.
So I'm new to generics. But generics seem like a great way to reduce code. here is the scenario. I have a MVC Web API.
http://www.google.com/{controller}/{chartType}/{id}
NOTE: id is optional
I have several chart types which return similar objects:
HourlyDeviceChart
HourlyUsersCharrt
HourlyAvgProcessingTime
etc..
I would like to have just one method that evaluates the chart type parameter and executes the corresponding actions. instead of 8 or 10 methods.
I would be accepting if my design needs some refactoring. I'm open to suggestions. The idea here is to reduce some code. I would hate to have 10 methods exposed in the Web API and then 10 more corresponding methods in another class. Just seems redundant.
As always your suggestions are welcomed!
The method exposed by the API:
IEnumerable<T> GetChart(string chartType)
{
switch(chartType)
{
case "DeviceChart":
return repository.HourlyDeviceChart();
break;
case "UserChart":
return repository.HourlyUsersChart();
break;
}
}
//Then the class that handles all the work would look something like the below
IEnumerable<HourlyDeviceChart> HourlyDeviceChart()
{
// select appropriate items from the queue
// populate HourlyDeviceChart object
// add object to list
// return HourlyDeviceChart list
}
IEnumerable<UserDeviceChart> HourlyUsersChart()
{
// do more of the same
}
You can use generics like this:
interface IChart {
bool IsCharItemNeeded(IChartItem item);
void AddChartItem(IChartItem item);
}
IEnumerable<T> Charts<T>() where T : new, IChart {
var res = List<T>();
foreach (QueueCommand command in MyBigQueue) {
var chart = new T();
foreach (IChartItem item in command) {
if (chart.IsCharItemNeeded(item)) {
chart.AddChartItem(item);
}
}
res.Add(chart);
}
return res;
}
All chart types need to implement the common IChart interface. The where T : new, IChart line provides a constraint that lets you call new T(); for that, all chart classes must also implement a no-argument constructor.
Now you can use your generic code like this:
IEnumerable<UserChart> userCharts = Charts<UserChart>();
IEnumerable<DeviceChart> deviceCharts = Charts<DeviceChart>();
If both HourlyUserChart and HourlyDeviceChart methods work in same fashion, then dasblinkenlight's answer is good, you can have one generic way of populating them. If you need to populate them differently in two repository methods, may be something like these will do:
1)
interface IHourlyChart {
IEnumerable<IHourlyChart> Create();
}
class HourlyDeviceChart : IHourlyChart
{
public IEnumerable<IHourlyChart> Create()
{
return repository.HourlyDeviceChart();
}
}
class HourlyUsersChart : IHourlyChart
{
public IEnumerable<IHourlyChart> Create()
{
return repository.HourlyUsersChart();
}
}
IEnumerable<T> GetChart<T>() where T : IHourlyChart, new()
{
return (IEnumerable<T>)new T().Create();
}
2) Or make it a tad more strongly typed via generics.
interface IHourlyChart<T> where T : IHourlyChart<T> {
IEnumerable<T> Create();
}
class HourlyDeviceChart : IHourlyChart<HourlyDeviceChart>
{
public IEnumerable<HourlyDeviceChart> Create()
{
return repository.HourlyDeviceChart();
}
}
class HourlyUsersChart : IHourlyChart<HourlyUsersChart>
{
public IEnumerable<HourlyUsersChart> Create()
{
return repository.HourlyUsersChart();
}
}
IEnumerable<T> GetChart<T>() where T : IHourlyChart, new()
{
return new T().Create();
}
3) Or some reflection, which is still better than your type checking:
IEnumerable<T> GetChart<T>() where T : IHourlyChart, new()
{
//find necessary method and invoke. may be:
return repository.GetType()
.GetMethods()
.Single(x => x.ReturnType == typeof(IEnumerable<T>))
.Invoke(repository, new object[0]) as IEnumerable<T>;
}
4) Worst case, do type checking inside your generic method, but check on the type itself, not any magic strings which is very brittle.
IEnumerable<T> GetChart<T>()
{
if (typeof(T) == typeof(HourlyDeviceChart))
return (IEnumerable<T>)repository.HourlyDeviceChart();
else if (typeof(T) == typeof(HourlyUsersChart))
return (IEnumerable<T>)repository.HourlyUsersChart();
// throw;
}
Call them all like:
var chartables = GetChart<HourlyUserChart>(); //etc
You should be able to do this by using a new interface and applying a constraint to your method GetChart
//Interface with a Type parameter to specify the return type of the method
public interface IChart<T>
{
IEnumerable<T> HourlyChart();
}
//How to implement the interface
public class HourlyDeviceChart : IChart<HourlyDeviceChart>
{
public static IEnumerable<HourlyDeviceChart> HourlyChart()
{
//Do work
}
}
//Your new method with a constraint applied
IEnumerable<T> GetChart<T>(string chartType) where T : IChart<T>
{
return T.HourlyChart();
}
Can someone help me figure out how to implement this method generically? The compiler complains that it cannot resolve t.Id. Which makes sense but, how do I tell it that all objects that pass will have an Id property. Here is the interface I defined for T:
namespace LiveWire.Model
{
public interface ILiveWireModel
{
Guid Id { get; }
}
}
The interface for all repositories:
internal interface ILiveWireRepository<T>
{
ICacheProvider Cache { get; }
string CacheKey { get; }
SqlConnection CreateConnection();
IEnumerable<T> GetData<TD>();
IEnumerable<T> LoadData<TD>();
Dictionary<Guid, T> GetCachedData<TD>();
void ClearCache();
}
And my method:
public IEnumerable<T> GetData<TD>()
where TD : ILiveWireModel
{
var data = GetCachedData<TD>();
if (data == null)
{
data = LoadData<TD>().ToDictionary(t => t.Id);
if (data.Any())
{
Cache.Set(CacheKey, data, 30);
}
}
return data.Values;
}
I'm including the whole class here which I hope will clear some things up.
internal abstract class LiveWireRepositoryBase<T> : ILiveWireRepository<T>
{
public ICacheProvider Cache { get; private set; }
public string CacheKey { get; private set; }
internal LiveWireRepositoryBase()
{
Cache = new DefaultCacheProvider();
}
public SqlConnection CreateConnection()
{
return new SqlConnection(
ConfigurationManager
.ConnectionStrings["LiveWire4Database"]
.ConnectionString);
}
public IEnumerable<T> GetData<TD>()
where TD : ILiveWireModel
{
var data = GetCachedData<TD>();
if (data == null)
{
data = LoadData<TD>().ToDictionary(t => t.Id);
if (data.Any())
{
Cache.Set(CacheKey, data, 30);
}
}
return data.Values;
}
public IEnumerable<T> LoadData<TD>()
{
return new List<T>();
}
public Dictionary<Guid, T> GetCachedData<TD>()
{
throw new NotImplementedException();
}
public void ClearCache()
{
throw new NotImplementedException();
}
}
I'm getting this error which I don't understand. I tried using an explicit interface implementation but, that wound up making me remove my where constraint.
The constraints for type parameter 'TD' of method 'LiveWire.Data.Repositories.LiveWireRepositoryBase.GetData()' must match the constraints for type parameter 'TD' of interface method 'LiveWire.Data.Repositories.ILiveWireRepository.GetData()'. Consider using an explicit interface implementation instead. C:\projects\LiveWire\Solution\LiveWire.Data\Repositories\LiveWireRepositoryBase.cs 32 31 LiveWire.Data
You'll be able to make this method compile by changing the class's signature to
public sealed class MyCache<T> where T : ILiveWireModel
(or, if the class is in a different namespace, where T : LiveWire.Model.ILiveWireModel).
That said, I'm not sure that this change will solve your problem. I have only seen a few snippets of your project's code, so I may be wrong, and take the following with a grain of salt:
Is it really the best design to keep GUID-keyed and integer-keyed values in the same cache? Presumably, you're taking data from two different sources, one which uses GUID keys and one which uses integer keys. But in the future, what if you add a third source, which also uses integer keys? The keys from the two integer-key sources could clash, and your cache would always be wrong for some queries. Personally, I'd maintain a second table or function (maybe keep a table of mappings for integer-valued keys, just pass through the GUID-valued keys) somewhere that knows the mapping from objects to keys, and use that function whenever I need to check if an object is cached. All the rest of the time, then, your cache could work directly in terms of keys and values, and not have to mess with different types of keys.
The exception you get at this stage just says that the interface definition
IEnumerable<T> GetData<TD>();
hasn't got the same constraints (i.e. the where) for the type parameter TD as the implementation
public IEnumerable<T> GetData<TD>() where TD : ILiveWireModel
You need to put the same constraint in the interface.
public IEnumerable<T> GetData<T>() where T:LiveWire.Model.ILiveWireModel {
//.../
}
Specialization of generics.
You need to fix the declaration first
public IEnumerable<T> GetData<T>()
then, in order to know what you can use ON T, you have to tell it what T is allowed to be.
public IEnumerable<T> GetData<T>() where T : ILiveWireModel
Finally, you haven't told us what var data actually contains, that would be inside of the GetCachedData and the LoadData Functions, which you dont pass T into and we dont have any idea what it returns.
I would expect to see something like this though
public IEnumerable<T> GetData<T>() where T : ILiveWireModel
{
var data = GetCachedData<T>();
if (data == null)
{
data = LoadData<T>().ToDictionary(t => t.Id);
if (data.Any())
{
Cache.Set(CacheKey, data, 30);
}
}
return data.Values;
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
To return IQueryable<T> or not return IQueryable<T>
I have LINQ to SQL repository implemented as follows. The GetAll method is returing a generic List instead of IQueryable. However in most of the examples and tutorials pit is shown to return IQueryable. What is the advantage of returing IQueryable ?
using System.Linq;
namespace RepositoryLayer
{
public interface IRepository<T> where T : class
{
//System.Linq.IQueryable<T> GetAll();
System.Collections.Generic.List<T> GetAll();
}
public class Repository<T> : IRepository<T> where T : class
{
public System.Data.Linq.DataContext Context
{
get;
set;
}
//public virtual System.Linq.IQueryable<T> GetAll()
//{
// //GetAll is returning generic Queryable<T>.
// System.Linq.IQueryable<T> allItems = Context.GetTable<T>();
// return allItems;
//}
public virtual System.Collections.Generic.List<T> GetAll()
{
System.Linq.IQueryable<T> allItems = Context.GetTable<T>();
return allItems.ToList();
}
}
}
Business Layer
namespace BusinessLayerProject
{
public class AccountBusiness
{
//IRepository<T>
RepositoryLayer.IRepository<RepositoryLayer.Account> accountRepository;
public AccountBusiness(RepositoryLayer.IRepository<RepositoryLayer.Account> repo)
{
accountRepository = repo;
}
//public List<RepositoryLayer.Account> GetAllAccounts()
//{
// //LibraryManagementClassesDataContext context = new LibraryManagementClassesDataContext();
// //List<RepositoryLayer.Account> accontList = context.Accounts.ToList();
// System.Linq.IQueryable<RepositoryLayer.Account> acc = accountRepository.GetAll();
// return acc.ToList();
//}
public List<RepositoryLayer.Account> GetAllAccounts()
{
List<RepositoryLayer.Account> acc = accountRepository.GetAll();
return acc;
}
}
}
READING
Advantage of creating a generic repository vs. specific repository for each object?
Using IQueryable let LINQ move some additional work into DB by creating different SQL queries. eg. when you try something like GetAll().Where(condition) and use List all items are queried from DB and where condition is checked application-side. When you use IQueryable it can be moved to DB and proper items are returner directly from there.
IQueryable extends IEnumerable. Both do not project/inflate their data until being iterated, whereas IList objects pull all their data and are populated when assigned to.
So it's a "lazy-load" vs. "eager-load" distinction.
Becasue IList is - ah - not smart?
Here we go:
IIF yo uexport IQueryable - on the Get method it is the only method you ever need. All parameters go into the IQueryable and BECAUSE OF DELAYED EXECUTION END UP IN YOUR SQL LAYER.
Export IList and you GET ALL and THEN filter - in memory, which is as much a perversion of LINQ as it gets.
The real trick here is that if I makcal your Get method and then .Where, OrderBy, that gets into the sql statement in the database.