I am developing in ASP.NET MVC3 and EntityFramework.
I want my model to follow an interface :
public class Account : IAccount
{
public string Id { get; set; }
public DateTime Date { get; set; }
public string Language { get; set; }
}
public interface IAccount
{
string Id { get; set; }
DateTime Date { get; set; }
string Language { get; set; }
}
Here's my Context
public class EFContext : DbContext, IContext
{
public DbSet<Account> Accounts { get; set; }
}
And here's the repository :
public interface IRepository<T> where T : class
{
IQueryable<T> All { get; }
int Count { get; }
bool Contains(Expression<Func<T, bool>> predicate);
void Create(T item);
void Update(T item);
void Delete(Expression<Func<T, bool>> predicate);
void Delete(T item);
}
public class EFRepository<T> : IRepository<T> where T : class
{
private EFContext _context;
public EFRepository(IUnitOfWork uow)
{
this._context = (EFContext)uow.Context;
}
protected DbSet<T> DbSet
{
get
{
return _context.Set<T>();
}
}
public IQueryable<T> All
{
get
{
return DbSet.AsQueryable();
}
}
public virtual int Count
{
get
{
return DbSet.Count();
}
}
public bool Contains(Expression<Func<T, bool>> predicate)
{
return DbSet.Count(predicate) > 0;
}
public virtual void Create(T item)
{
DbSet.Add(item);
}
public virtual void Update(T TObject)
{
var item = DbSet.Attach(TObject);
_context.SetItemState(TObject, EntityState.Modified);
}
public virtual void Delete(Expression<Func<T, bool>> predicate)
{
var objects = DbSet.Where(predicate);
foreach (var obj in objects)
{
DbSet.Remove(obj);
}
}
public virtual void Delete(T TObject)
{
DbSet.Remove(TObject);
}
}
Now, I want to use IRepository<IAccount> but this will ask the context for DbSet<IAccount>. This leads to an error since the Context contains a DbSet<Account>.
I then tried the solution proposed here for Linq2Sql : http://iridescence.no/post/Linq-to-Sql-Programming-Against-an-Interface-and-the-Repository-Pattern.aspx
So I added this function to my EFContext
public new DbSet<T> Set<T>() where T : class
{
var ciccio = TableMaps[typeof(T)];
return (DbSet<T>)base.Set(ciccio).Cast<T>();
}
But it doesn't work.
Do anyone have a suggestion?
Thx
What benefit are you receiving from using an interface for your entities? I don't see any value here. Typically, you use Interfaces to remove dependencies upon the implementation, but that's not what you're achieving here because you're returning a concrete DbSet of objects.
Your entities are already Poco's. They don't have dependencies on other implemntations, and they have no code in them other than a getter/setter. Using an interface is redundant and pointless.
I've found a workaround. I kind of like it so I want to share it.
I rewritten my EFRepository :
public class EFRepository<T, W> :
IRepository<T> where T : class
where W : class, T
{
private EFContext _context;
public EFRepository(IUnitOfWork uow)
{
this._context = (EFContext)uow.Context;
}
protected DbSet<W> DbSet
{
get
{
return _context.Set<W>();
}
}
public IQueryable<T> All
{
get
{
return DbSet.AsQueryable<T>();
}
}
public virtual int Count
{
get
{
return DbSet.Count();
}
}
public bool Contains(Expression<Func<T, bool>> predicate)
{
return All.Count(predicate) > 0;
}
public virtual void Create(T item)
{
DbSet.Add(item as W);
}
public virtual void Update(T TObject)
{
var item = DbSet.Attach(TObject as W);
_context.SetItemState(TObject, EntityState.Modified);
}
public virtual void Delete(Expression<Func<T, bool>> predicate)
{
var objects = All.Where(predicate);
foreach (var obj in objects)
{
DbSet.Remove(obj as W);
}
}
public virtual void Delete(T TObject)
{
DbSet.Remove(TObject as W);
}
}
So now basically all I need to do now is
IRepository<IAccount>> accRepository = new EFRepository<IAccount, Account>(uow);
I am happy with this solution, but still I'm not sure it is the best one, so any comments will be appreciated.
Thanks
Related
I tried to implement the function without success
I want to check if the user's status is true so that means he is logged in
I mean if Status is false then I do not want to display it at all in a list that will be ignored
What I tried causes all the connected to be displayed even if they are false
Model:
[Table("Contact")]
public partial class Contact
{
[Key]
public Guid Id { get; set; }
public string DisplayName { get; set; } = null!;
public string ProfilePic { get; set; } = null!;
public int? Rating { get; set; }
public bool? Status { get; set; }
public bool? IsRegistration { get; set; }
}
DbContext:
public virtual DbSet<Contact> Contacts { get; set; } = null!;
Repository:
private readonly TalkBackContactsDbContext _context;
public ContactsRepository(TalkBackContactsDbContext context)
{
_context = context;
}
public IQueryable<Contact> GetAllConnectedUser(Contact contact)
{
if (contact.Status == false)
{
throw new Exception("Not exist");
}
else
{
return _context.Contacts;
}
}
api controller:
private readonly IContactsRepository _repo;
public ContactsController(IContactsRepository repo)
{
_repo = repo;
}
[HttpGet()]
public IEnumerable<Contact> GetAllConnected()
{
var contact = new Contact();
try
{
return _repo.GetAllConnectedUser(contact);
}
catch (Exception e)
{
e.ToString();
}
return _repo.GetAllConnectedUser(contact);
}
Try this.
Repository:
private readonly TalkBackContactsDbContext _context;
public ContactsRepository(TalkBackContactsDbContext context)
{
_context = context;
}
public IEnumerable<Contact> GetAllConnectedUser()
{
_context.Contacts.Where(a=>a.Status==true).AsEnumerable();
}
api controller:
private readonly IContactsRepository _repo;
public ContactsController(IContactsRepository repo)
{
_repo = repo;
}
[HttpGet()]
public IEnumerable<Contact> GetAllConnected()
{
return _repo.GetAllConnectedUser();
}
I tried to use the existing database in my application but every time I hit the view it says
An unhandled exception occurred while processing the
InvalidOperationException: Unable to resolve service for type
'BookStore.Models.BookStoreContext' while attempting to activate
'BookStore.Models.UsersRepo'
Context
namespace BookStore.Models
{
public partial class BookStoreContext : DbContext
{
public BookStoreContext()
{
}
public BookStoreContext(DbContextOptions<BookStoreContext> options)
: base(options)
{
}
public virtual DbSet<Users> Users { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("Server=(localdb)\\V11.0;Database=BookStore;Trusted_Connection=True;");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasAnnotation("ProductVersion", "2.2.3-servicing-35854");
modelBuilder.Entity<Users>(entity =>
{
entity.HasKey(e => e.UserId);
entity.Property(e => e.UserId).HasColumnName("User_ID");
entity.Property(e => e.Password)
.IsRequired()
.HasMaxLength(50);
entity.Property(e => e.UserName)
.IsRequired()
.HasColumnName("User_Name")
.HasMaxLength(50);
});
}
}
}
User Repository
namespace BookStore.Models
{
public class UsersRepo : IUser
{
private readonly BookStoreContext _bookStoreContext;
public UsersRepo(BookStoreContext bookStoreContext)
{
_bookStoreContext = bookStoreContext;
}
public void AddUser(Users users)
{
_bookStoreContext.Users.Add(users);
_bookStoreContext.SaveChanges();
}
}
}
User Model
public partial class Users
{
public long UserId { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public int Type { get; set; }
}
public interface IUser
{
void AddUser(Users users);
}
User Controller
public class UsersController : Controller
{
private readonly IUser _userRepo;
public UsersController(IUser userRepo)
{
_userRepo = userRepo;
}
[HttpGet]
public IActionResult Index()
{
return View();
}
[HttpPost]
public IActionResult Index(Users users)
{
_userRepo.AddUser(users);
return RedirectToAction("UserAddedSuccessfully");
}
public IActionResult UserAddedSuccessfully()
{
return View();
}
}
I tried this one and it is perfectly working
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<BookStoreContext>();
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}
Let say I have classes hierarchy like
public class A
{
public int AMember { get; set; }
}
public class B
{
public int BMember { get; set; }
public virtual A AasMember { get; set; }
}
public static class OrderByUtility
{
public static bool PropertyExists<T>(string propertyName)
{
return typeof(T).GetProperty(propertyName, BindingFlags.IgnoreCase |
BindingFlags.Public) != null;
}
}
From main class whenever I use this Utility
OrderByUtility.PropertyExists BClass>("BMember");
This works fine and returns TRUE. But whenever I use
OrderByUtility.PropertyExists BClass> ("AMember"); returns False
I want same PropertyExist function work for all Composed Object. Please suggest resolving this issue. Thanks
Here is a really naive implementation of it. You could make it recursive to keep checking nested types. It also keeps a cache so it doesn't do the expensive processing on each lookup.
public class A
{
public int AMember { get; set; }
}
public class B
{
public int BMember { get; set; }
public virtual A AasMember { get; set; }
}
public static class OrderByUtility
{
private static readonly Dictionary<Type, Dictionary<string, bool>> Seen =
new Dictionary<Type, Dictionary<string, bool>>();
public static bool PropertyExists<T>(string propertyName)
{
var type = typeof(T);
if (!Seen.TryGetValue(type, out var props))
{
props = new Dictionary<string, bool>();
Seen[type] = props;
}
if (props.ContainsKey(propertyName))
{
return props[propertyName];
}
var prop = GetPropertyByName(type, propertyName);
if (prop == null)
{
foreach (var p in type.GetProperties())
{
var propType = p.PropertyType;
if (!propType.IsClass && !propType.IsInterface) continue;
prop = GetPropertyByName(propType, propertyName);
if (prop != null)
{
break;
}
}
}
props[propertyName] = prop != null;
return props[propertyName];
}
private static PropertyInfo GetPropertyByName(Type t, string name)
{
return t.GetProperty(name, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
}
}
Usage:
bool exists = OrderByUtility.PropertyExists<B>("AMember");
Suppose you have a collection of collection
Eg : CEO-> Vps-> GMs ->..
CEO will contain collection of VP's, VP's will have collection of GM's and so on.
Suppose you need to find a particular GM is the alias is given. Write a linq query to get the employee details if the employee alias is given.
You could try something like below
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
CeoCollection myCEOs = new CeoCollection();
var myGM = myCEOs.SelectMany(a => a.DummyVps.SelectMany(b => b.DummyGms.FindAll(c => c.Alias == "VeryDumb")));
}
}
public abstract class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string Alias { get; set; }
}
public class CeoCollection : List<Ceo> { }
public class Ceo : Employee
{
public VpCollection DummyVps { get; set; }
}
public class VpCollection : List<Vp> { }
public class Vp : Employee
{
public GmCollection DummyGms { get; set; }
}
public class GmCollection : List<Gm> { }
public class Gm : Employee
{
}
}
The end goal for this post is to override the ToString() method of a concrete implementation of a generic base class while still being able to search the implementation using Linq flattening technique. So if you read this and see a better way let me know. I'm using Telerik controls for Silverlight and they won't change their api to allow some of their control properties to be data-bound and instead rely on the ToString() method of whatever object they are bound to. yea, stupid.. Anyway here is what I've got.
RadTreeView control on my page. The FullPath property of each node in the treeview uses the ToString() method of each item its bound to (so this is what I need to override).
I had to create an "intermediary" class to enhance my base model class so it can be bound as a heirarchy in the tree view and then a concrete implementation of that generic class to override ToString(). Now the problem is I have a Linq extension that explodes because it cannot convert the concrete implementation back to the base generic class. I love generics but this is too much for me. Need help on solving the extension method issue.
Intermediary generic class:
public class HeirarchicalItem<T> : NotifyPropertyChangedBase, INotifyCollectionChanged where T : class
{
public event NotifyCollectionChangedEventHandler CollectionChanged;
public virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs ea)
{
if (CollectionChanged != null)
CollectionChanged(this, ea);
}
public HeirarchicalItem() { }
public HeirarchicalItem(T item)
{
Item = item;
}
public HeirarchicalItem(IEnumerable<T> collection)
{
CopyFrom(collection);
}
private T _item;
public T Item
{
get
{
return _item;
}
set
{
_item = value;
RaisePropertyChanged<HeirarchicalItem<T>>(a => a.Item);
}
}
private ObservableCollection<HeirarchicalItem<T>> _children = new ObservableCollection<HeirarchicalItem<T>>();
public virtual ObservableCollection<HeirarchicalItem<T>> Children
{
get { return _children; }
set
{
_children = value;
RaisePropertyChanged<HeirarchicalItem<T>>(a => a.Children);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
private void CopyFrom(IEnumerable<T> collection)
{
if ((collection != null))
{
using (IEnumerator<T> enumerator = collection.GetEnumerator())
{
while (enumerator.MoveNext())
{
HeirarchicalItem<T> newHeirarchicalItem = new HeirarchicalItem<T>(enumerator.Current);
Children.Add(newHeirarchicalItem);
RaisePropertyChanged<HeirarchicalItem<T>>(a => a.Children);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add));
}
}
}
}
}
Base model class: (data is shuttled to and from WCF Ria service using this class)
public class tbl_Path : EntityBase, IFullPath, IEquatable<tbl_Path>, IEqualityComparer<tbl_Path>
{
public tbl_Path();
public int GetHashCode(tbl_Path obj);
public override string ToString();
public DateTime CreateDate { get; set; }
public short Depth { get; set; }
public string FullPath { get; set; }
public bool IsAuthorized { get; set; }
public bool IsSelected { get; set; }
public string Name { get; set; }
public override IEnumerable<Operation> Operations { get; }
public int? ParentPathID { get; set; }
public int PathID { get; set; }
public Guid SecurityKey { get; set; }
public EntityCollection<tbl_Configuration> tbl_Configuration { get; set; }
public EntityCollection<tbl_Key> tbl_Key { get; set; }
public EntityCollection<tbl_SecurityACL> tbl_SecurityACL { get; set; }
public EntityCollection<tbl_SecurityInheriting> tbl_SecurityInheriting { get; set; }
public EntityCollection<tbl_Variable> tbl_Variable { get; set; }
}
Concrete Implementation so that I can override ToString():
public class HeirarchicalPath : HeirarchicalItem<tbl_Path>
{
public HeirarchicalPath()
{
}
public HeirarchicalPath(tbl_Path item)
: base(item)
{
}
public HeirarchicalPath(IEnumerable<tbl_Path> collection)
: base(collection)
{
}
public override string ToString()
{
return Item.Name; **// we override here so Telerik is happy**
}
}
And finally here is the Linq extension method that explodes during compile time because I introduced a concrete implementation of my generic base class.
public static IEnumerable<T> Traverse<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> fnRecurse)
{
foreach (T item in source)
{
yield return item;
IEnumerable<T> seqRecurse = fnRecurse(item);
if (seqRecurse != null)
{
foreach (T itemRecurse in Traverse(seqRecurse, fnRecurse))
{
yield return itemRecurse;
}
}
}
}
Actual code that is breaking: (x.Children is highlighted with the error)
Cannot implicitly convert type
'System.Collections.ObjectModel.ObservableCollection<HeirarchicalItem<tbl_Path>>' to
'System.Collections.Generic.IEnumerable<HeirarchicalPath>'. An explicit conversion
exists (are you missing a cast?)
HeirarchicalPath currentItem = this.Paths.Traverse(x => x.Children).Where(x => x.Item.FullPath == "$/MyFolder/Hello").FirstOrDefault();
Figured it out. Been working on this all day and minutes after posting the question I resolve it as always.
Just needed to add this bit to my concrete implementation and no more compiler errors.
private ObservableCollection<HeirarchicalPath> _children = new ObservableCollection<HeirarchicalPath>();
public new ObservableCollection<HeirarchicalPath> Children
{
get
{
return _children;
}
set
{
if (value == null)
return;
_children = value;
RaisePropertyChanged<HeirarchicalPath>(a => a.Children);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}