Automapper to Map two List Classes of different structure and also Memberwise explicit Mapping - asp.net-web-api

I have 4 classes namely ClassA, ClassADto, ClassAA(inner class to ClassA) and the final Result class.
ClassAA
{
public int HouseNumber{get;set;}
public string StreetName{get;set;}
public string State{get;set;}
}
ClassA
{
public int Age{get;set;}
public string Name{get;set;}
public ClassAA AObj[get;set;}
}
ClassADto
{
public int Age{get;set;}
public string Name{get;set;}
}
class Result
{
public string StreetName{get;set;}
public int TotalCount{get;set;}
public int TodaysDate{get;set;}
public List<ClassADto> AObjectsList{get;set;}
}
Now my aim is map the 'Result' class with the List of ClassA object to fill it the property 'AObjectsList' as below:
Result data= map mapper.map>(obj);
Also at the same time in automapper i want to use custom function either using 'Resolve' or 'AfterMap' to set properties like 'TodaysDate' to current datetime of system and property 'TotalCount' by counting the number of data.
I tried in many ways using 'CreateMap' and also used 'ForMembers' as from 'classAA' we only need the 'StreetName' but it didn't work. Need some help please.

One time typing approach ;)
public static Result ToResult(this List<ClassA> users)
{
return new Result
{
TotalCount = users.Count,
TodaysDate = DateTime.Today,
AObjectsList = users
.Select(user => new ClassADto
{
Name = user.Name,
Age = user.Age
})
.ToList()
};
}
// Usage
var users = new List<ClassA> { new ClassA(), new ClassA() };
var result = users.ToResult();

Related

WebApi: property that is collection of complex objects is alwasy empty

I'm trying to return this class in web api:
public IEnumerable<Product> Get()
{
var fruits = new Category("Fruits");
var veggies = new Category("Veggies");
var apple = new Product("apple");
apple.Categories = new List<Category>() { fruits };
var potato = new Product("Potatoes");
potato.Categories = new List<Category>() { veggies };
var banana = new Product("Banana");
banana.Categories = new List<Category>() { fruits };
List<Product> list = new List<Product>(){
apple, potato, banana
};
return list;
}
For whatever reason the Categories collection is always returned empty...
Am I missing something ?
Thanks!
Update:
public class Category
{
public string Id { get; private set; }
public string Name { get; private set; }
public Category() { }
public Category(string name)
{
if (string.IsNullOrEmpty(name))
throw new ArgumentException("name must be set");
this.Name = name;
}
}
Aaand.. It won't show the categories because both properties in Category class don't have public setter.
Makes me wonder why serializer is checking for access modifier of setter.
Category class had 2 properties, both having private setter; properties with private setter won't be serialized.
I have verified that the private set issue have been fixed in web api RTM release.

How to test Singleton class that has a static dependency

I have a Singleton class that uses the thread-safe Singleton pattern from Jon Skeet as seen in the TekPub video. The class represents a cached list of reference data for dropdowns in an MVC 3 UI.
To get the list data the class calls a static method on a static class in my DAL.
Now I'm moving into testing an I want to implement an interface on my DAL class but obviously cannot because it is static and has only one static method so there's no interface to create. So I want to remove the static implementation so I can do the interface.
By doing so I can't call the method statically from the reference class and because the reference class is a singleton with a private ctor I can't inject the interface. How do I get around this? How do I get my interface into the reference class so that I can have DI and I can successfully test it with a mock?
Here is my DAL class in current form
public static class ListItemRepository {
public static List<ReferenceDTO> All() {
List<ReferenceDTO> fullList;
... /// populate list
return fullList;
}
}
This is what I want it to look like
public interface IListItemRepository {
List<ReferenceDTO> All();
}
public class ListItemRepository : IListItemRepository {
public List<ReferenceDTO> All() {
List<ReferenceDTO> fullList;
... /// populate list
return fullList;
}
}
And here is my singleton reference class, the call to the static method is in the CheckRefresh call
public sealed class ListItemReference {
private static readonly Lazy<ListItemReference> instance =
new Lazy<ListItemReference>(() => new ListItemReference(), true);
private const int RefreshInterval = 60;
private List<ReferenceDTO> cache;
private DateTime nextRefreshDate = DateTime.MinValue;
public static ListItemReference Instance {
get { return instance.Value; }
}
public List<SelectListDTO> SelectList {
get {
var lst = GetSelectList();
lst = ReferenceHelper.AddDefaultItemToList(lst);
return lst;
}
}
private ListItemReference() { }
public ReferenceDTO GetByID(int id) {
CheckRefresh();
return cache.Find(item => item.ID == id);
}
public void InvalidateCache() {
nextRefreshDate = DateTime.MinValue;
}
private List<SelectListDTO> GetSelectList() {
CheckRefresh();
var lst = new List<SelectListDTO>(cache.Count + 1);
cache.ForEach(item => lst.Add(new SelectListDTO { ID = item.ID, Name = item.Name }));
return lst;
}
private void CheckRefresh() {
if (DateTime.Now <= nextRefreshDate) return;
cache = ListItemRepository.All(); // Here is the call to the static class method
nextRefreshDate = DateTime.Now.AddSeconds(RefreshInterval);
}
}
}
You can use the singleton based on instance(not based on static), for which you can declare interface like this.
public interface IListItemRepository
{
List<ReferenceDTO> All();
}
public class ListItemRepository : IListItemRepository
{
static IListItemRepository _current = new ListItemRepository();
public static IListItemRepository Current
{
get { return _current; }
}
public static void SetCurrent(IListItemRepository listItemRepository)
{
_current = listItemRepository;
}
public List<ReferenceDTO> All()
{
.....
}
}
Now, you can mock IListItemRepository to test.
public void Test()
{
//arrange
//If Moq framework is used,
var expected = new List<ReferneceDTO>{new ReferneceDTO()};
var mock = new Mock<IListItemRepository>();
mock.Setup(x=>x.All()).Returns(expected);
ListItemRepository.SetCurrent(mock.Object);
//act
var result = ListItemRepository.Current.All();
//Assert
Assert.IsSame(expected, result);
}
Which DI framework are you using? Depending on your answer, IOC container should be able to handle single-instancing so that you don't have to implement your own singleton pattern in the caching class. In your code you would treat everything as instanced classes, but in your DI framework mappings you would be able to specify that only one instance of the cache class should ever be created.
One way to test it would be if you refactor your ListItemReference by adding extra property:
public sealed class ListItemReference {
...
public Func<List<ReferenceDTO>> References = () => ListItemRepository.All();
...
private void CheckRefresh() {
if (DateTime.Now <= nextRefreshDate) return;
cache = References();
nextRefreshDate = DateTime.Now.AddSeconds(RefreshInterval);
}
}
And then in your test you could do:
ListItemReference listReferences = new ListItemReference();
listReferences.References = () => new List<ReferenceDTO>(); //here you can return any mock data
Of course it's just temporary solution and I would recommend getting rid of statics by using IoC/DI.

MVC3 razor based htmlhelper with lambda field expressions based on model

I am creating a fluent HtmlHelper in MVC - to create a grid based on HTML.
I am aware of mvc contrib and WebGrid - but I am making my own and have a specific problem:
I have to enter this:
#Html.DSGridFor().AddColumn(x=>x.FirstOrDefault().Message)
but I want to be able to type this:
#Html.DSGridFor().AddColumn(x=>x.Message)
The code that gets called when I start with #Html.DSGridFor() - taking in the page based model.
public static DSGridHelper<TModel> DSGridFor<TModel>(this HtmlHelper<TModel> html)
{
return new DSGridHelper<TModel>(html);
}
and then within the class DSGridHelper I have this:
public DSGridHelper<TModel> AddColumn(Expression<Func<TModel, dynamic>> property, string HeaderText = null)
{
string ColumnName = (property.Body as MemberExpression).Member.Name;
DSGridColumn DSGC = new DSGridColumn();
DSGC.ColumnName = ColumnName;
DSGC.HeaderText = HeaderText ?? ColumnName;
DSColumnList.Add(DSGC);
return this;
}
public List<DSGridColumn> DSColumnList { get; set; }
and the column class at the moment is really basic:
public class DSGridColumn
{
public DSGridColumn()
{
}
public string ColumnName { get; set; }
public string HeaderText { get; set; }
}
I can get this code working fine with string based column names, but I want the declaring code in the razor page to be simple in format and strongly typed. At the moment I have to type x=>x.First().Message but I really only need x=>x.Message to identify the column.
I appreciate any help.
UPDATE
Thanks to Justin I can now provide my/our code.
View:
#(Html.DSGridFor3().AddColumn(x => x.Message)
.AddColumn(x => x.Host)
.ToMvcString())
HTML Helper call:
public static DSGridHelper3<T> DSGridFor3<T>(this HtmlHelper<IEnumerable<T>> htmlHelper)
{
return new DSGridHelper3<T>(htmlHelper);
}
Returning class:
public class DSGridHelper3<T>
{
private HtmlHelper _htmlHelper;
//private IEnumerable<T> _dataList;
public List<DSGridColumn> DSColumnList { get; set; }
public DSGridHelper3(HtmlHelper<IEnumerable<T>> htmlHelper)
{
_htmlHelper = htmlHelper;
// _dataList = htmlHelper.ViewData.Model;
DSColumnList = new List<DSGridColumn>();
}
public DSGridHelper3<T> AddColumn(Expression<Func<T, object>> property)
{
string columnName = (property.Body as MemberExpression).Member.Name;
DSGridColumn DSGC = new DSGridColumn();
DSGC.ColumnName = columnName;
DSGC.HeaderText = columnName;
DSColumnList.Add(DSGC);
return this;
}
public MvcHtmlString ToMvcString()
{
sb.Append("<table>");
sb.Append("<tr>");
sb.Append("<td>");
sb.Append("hello world within a table");
sb.Append(#"</td>");
sb.Append("<td>");
sb.Append("hello world within a table");
sb.Append(#"</td>");
sb.Append(#"</tr>");
sb.Append(#"</table>");
return new MvcHtmlString(sb.ToString());
}
}
UPDATE 2
If you wanted to manually insert a different type (perhaps because you are going to get a small amount of table data from ViewData rather than the model of the page) then here is some more code:
View:
#(Html.DSGridFor3<DanSoftware.MVC.Areas.Errors.Code.ELMAH_Error>().AddColumn(x => x.Message).ToMvcString();)
Alternative signature for the DSGridHelper ...helper
public static DSGridHelper3<T> DSGridFor3<T>(this HtmlHelper htmlHelper)
{
return new DSGridHelper3<T>(htmlHelper);
}
Additional constructor:
public DSGridHelper3(HtmlHelper htmlHelper)
{
_htmlHelper = htmlHelper;
// _dataList = htmlHelper.ViewData.Model;
DSColumnList = new List<DSGridColumn>();
}
Hope this helps someone and thanks Justin!
I dont have Visual Studio with me but I'll take a stab at this...
I would take in a collection as a datatype either in your DsGridFor method or in the AddColumn method. This will allow you to send Strongly-typed arguments from a collection. Say you wanted a generic method of AddColumn for a given collection with access to the class properties vs the collection methods, it would look something like this (just an example):
public static DSGridHelper<T> AddColumn<T>(this HtmlHelper<IEnumerable<T>> htmlHelper, Expression<Func<T, object>> property) where T : class
{
string columnName = (property.Body as MemberExpression).Member.Name;
DSGridColumn DSGC = new DSGridColumn();
DSGC.ColumnName = ColumnName;
DSGC.HeaderText = HeaderText ?? ColumnName;
DSColumnList.Add(DSGC);
return this;
}
For your situation, to new-up a DsGridHelper class I might explicitly set a model-type first and then add overloads as I go:
public static DSGridHelper<T> DSGridFor<T>(this HtmlHelper<IEnumerable<T>> htmlHelper) where T : class
{
return new DSGridHelper<T>(htmlHelper);
}
And then my DsGridHelper might look something like this:
public class DsGridHelper<T>
{
private HtmlHelper _htmlHelper;
private IEnumerable<T> _dataList;
public DsGridHelper(HtmlHelper<IEnumerable<T>> htmlHelper)
{
_htmlHelper = htmlHelper;
_dataList = htmlHelper.ViewData.Model;
}
public DsGridHelper<T> AddColumn(Expression<Func<T, object>> property)
{
string columnName = (property.Body as MemberExpression).Member.Name;
DSGridColumn DSGC = new DSGridColumn();
DSGC.ColumnName = ColumnName;
DSGC.HeaderText = HeaderText ?? ColumnName;
DSColumnList.Add(DSGC);
return this;
}
}

ASP.NET MVC Patterns

I am fairly new to MVC, but after playing with it (MVC 3/Razor), I am hooked.
I have a few questions:
1) What is the best, or most widely used pattern to develop MVC apps in? Repository, DDD, UOW?
2) I am using the Entity Framework 4, so could some please explain to me or point me to a good source that will explain the Repository Pattern w/EF4? Doesn't EF4 take place as the business layer and the data access layer? Does the Repository Pattern even provide a benefit?
3) Also, one last question, could someone explain the whole relationship between the Controller, the Model and the View? I get the basics, but maybe a little more in depth of the correct way to use it. View Models - Say I have a view that displays customer info, and one that edits it, should I have a view model and an edit model, or can the be passed around?
4) Examples??
Thanks for the help up front,
$("Sam")
** EDIT **
Am I on the right track here:
Public Class HomeController
Inherits System.Web.Mvc.Controller
Function Index(ByVal id As Integer) As ActionResult
Return View(New HomeModel)
End Function
<HttpPost()> _
Function Index(ByVal Model As HomeModel) As ActionResult
Return View(Model)
End Function
End Class
Public Class HomeModel
Private _Repository As IRepository(Of Customer)
Public Property Customer As Customer
Public Sub New()
End Sub
Public Sub New(ByVal ID As Integer)
_Repository = New CustomerRepository
Customer = _Repository.GetByID(ID)
End Sub
End Class
Public Interface IRepository(Of T)
Function GetByID(ByVal ID As Integer) As T
Sub Add(ByVal Entity As T)
Sub Delete(ByVal Entity As T)
End Interface
Public Class CustomerRepository
Implements IRepository(Of Customer)
Public Sub Add(ByVal Entity As Customer) Implements IRepository(Of Customer).Add
End Sub
Public Sub Delete(ByVal Entity As Customer) Implements IRepository(Of Customer).Delete
End Sub
Public Function GetByID(ByVal ID As Integer) As Customer Implements IRepository(Of Customer).GetByID
Return New Customer With {.ID = ID, .FirstName = "Sam", .LastName = "Striano"}
End Function
End Class
Public Class Customer
Public Property ID As Integer
Public Property FirstName As String
Public Property LastName As String
End Class
I use generic repositories that get instantiated in a service class (using Dependency Injection with Ninject).
The service class essentially performs two functions:
It provides all the methods that the controller will consume.
It has a property called ViewModel, that essentially maps the data that the views need into a MyViewModel class.
The Controller consumes the service class. With this "pattern", your controllers look like:
namespace ES.eLearningFE.Areas.Courses.Controllers
{
public partial class CourseController : Controller
{
ICourseDisplayService service;
public CourseController(ICourseDisplayService service)
{
this.service = service;
}
public virtual ActionResult Display(int CourseId, int StepOrder, string PupilName, string TutorName)
{
service.CourseId = CourseId;
service.StepOrder = StepOrder;
service.PupilName = PupilName;
service.TutorName = TutorName;
if (Request.IsAjaxRequest())
{
return PartialView(service.ViewModel);
}
else
{
return View(service.ViewModel);
}
}
}
}
The ViewModel class only hold display data and no methods (except the odd really simple method to retrieve data from another property that is, for example a List<> object).
Works really well. An example of a service class:
namespace ES.eLearning.Domain.Services.Courses
{
public class SqlCourseDisplayService : ICourseDisplayService
{
DataContext db;
public SqlCourseDisplayService(DbDataContextFactory contextFactory)
{
db = contextFactory.Make();
CoursesRepository = new SqlRepository<Course>(db);
StepsRepository = new SqlRepository<CourseStep>(db);
StepLinksRepository = new SqlRepository<StepLink>(db);
UserCoursesRepository = new SqlRepository<UserCourse>(db);
CourseTutorsRepository = new SqlRepository<CourseTutor>(db);
UsersRepository = new SqlRepository<User>(db);
}
#region ICourseDisplayService Members
public ViewModels.CourseDisplayVM ViewModel
{
get
{
return new ViewModels.CourseDisplayVM
{
CourseId = this.CourseId,
CourseName = this.Course.Name,
Steps = this.Steps,
ActiveStepIndex = this.ActiveStepIndex,
CurrentStepIndex = this.CurrentStepIndex,
Pupil = new UserDto { UserId = this.PupilId, UserName = this.PupilName },
Tutors = this.GetTutors(this.CourseId),
Tutor = tutorName == null ? null : new UserDto { UserName = this.TutorName, UserId = this.TutorId}
};
}
}
#region Entities
int courseId;
public int CourseId
{
get
{
if (courseId == 0) throw new ApplicationException("Invalid Course Id!");
return courseId;
}
set
{
if (value == 0) throw new ApplicationException("Invalid Course Id!");
try
{
Course = (from c in CoursesRepository.Query where c.CourseId == value select c).First();
Steps = Course.CourseSteps.ToList();
courseId = value;
}
catch {throw new ApplicationException("No Course found for Course Id: " + value);}
}
}
public Data.Course Course { get; private set; }
public int StepOrder { get; set; }
public List<Data.CourseStep> Steps { get; private set; }
public int ActiveStepIndex
{
get
{
if (PupilName == null)
{
throw new ApplicationException("Pupil not set!");
}
if (CourseId == 0)
{
throw new ApplicationException("Course not set!");
}
try
{
var x = (from uc in UserCoursesRepository.Query where (uc.IdCourse == CourseId) && (uc.UserName == PupilName) select uc).First();
return x.ActiveStepIndex;
}
catch { throw new ApplicationException("Could not get Active Step!"); }
}
}
#endregion
#region Users
string tutorName;
public string TutorName
{
get
{
if (tutorName == null) throw new ApplicationException("Invalid call to get Tutor Name [Null Tutor Name]!");
return tutorName;
}
set
{
tutorName = value;
TutorId = (Guid)Membership.GetUser(tutorName).ProviderUserKey;
}
}
public Guid TutorId { get; set; }
string pupilName;
public string PupilName
{
get { return pupilName; }
set
{
pupilName = value;
PupilId = (Guid)Membership.GetUser(pupilName).ProviderUserKey;
}
}
public Guid PupilId { get; set; }
#endregion
#region Utility Properties
public int CurrentStepIndex { get; set; }
public int StepCount
{
get
{
return Steps == null ? 0 : Steps.Count();
}
}
#endregion
#region Private Utilities
private List<UserDto> GetTutors(int CourseId)
{
return (from ct in CourseTutorsRepository.Query join u in UsersRepository.Query
on ct.TutorName equals u.UserName
where (ct.CourseId == courseId)
select new UserDto { UserName = ct.TutorName, UserId = u.UserId }).ToList();
}
#endregion
#region Repositories
private IRepository<Course> CoursesRepository
{
get;
set;
}
private IRepository<CourseStep> StepsRepository
{
get;
set;
}
private IRepository<StepLink> StepLinksRepository
{
get;
set;
}
private IRepository<UserCourse> UserCoursesRepository
{
get;
set;
}
private IRepository<CourseTutor> CourseTutorsRepository
{
get;
set;
}
private IRepository<User> UsersRepository
{
get;
set;
}
#endregion
#endregion
}
}
May not be everyone's choice, but hey, it works for me... AND (more importantly) my clients and their users.
Edit
As requested in the comment below, the Repository that I use:
namespace ES.eLearning.Domain
{
public class SqlRepository<T> : IRepository<T> where T : class
{
DataContext db;
public SqlRepository(DataContext db)
{
this.db = db;
}
#region IRepository<T> Members
public IQueryable<T> Query
{
get { return db.GetTable<T>(); }
}
public List<T> FetchAll()
{
return Query.ToList();
}
public void Add(T entity)
{
db.GetTable<T>().InsertOnSubmit(entity);
}
public void Delete(T entity)
{
db.GetTable<T>().DeleteOnSubmit(entity);
}
public void Attach(T entity)
{
db.GetTable<T>().Attach(entity);
}
public void Save()
{
db.SubmitChanges();
}
#endregion
}
}
And the IRepository Interface:
namespace Wingspan.Web.Mvc
{
public interface IRepository<TEntity> where TEntity : class
{
List<TEntity> FetchAll();
IQueryable<TEntity> Query {get;}
void Add(TEntity entity);
void Delete(TEntity entity);
void Attach(TEntity entity);
void Save();
}
}
This should help you getting started. There are a lot of tutorials and videos available; for example:
Understanding Models, Views and Controllers
The ASP.NET MVC 2.0 basics and excellent introduction by Scott Hanselman. Personally one of my favorite speakers.
And also at www.asp.net; there are a few tutorials/examples to help you getting started. For example the Music Store sample
Unfortunately, I'm not so familiar with EF4/Repository pattern. But here's a blogpost about this pattern.
1) I would say that the repository pattern is the most widely used, then there is inversion of controll too.
2) I can't really point out the benefits with using a repository for entity framework other than that the controller should not know about how to acces data other then asking a repository. This makes it easy to switch it out sometime.
You can also eager load the data to make sure that the view don't call the database in every iteration of a foreach, for example a collection of users to display data from a child entity. You can probly do this anyway, but I feel that the repository is the right place to do it.
3) I can't tell you about the concept in a more in depth way, but I can tell some about viewmodels. In my opinion you should only use viewmodels if there is anything more then one entity you want to send to the view, for example a list of countries. You can alo use a viewmodel to "flatten" out very complex objects.
I would defiantly say the repository pattern is used a lot. This pattern can be used with Dependency Injection. Using Dependency Injection makes Unit Testing a breeze because you can snap different repositories to an abstract repoistory. Check out http://ninject.org/ for a simple to use Dependecy injector for .NET.
View Models should hold display data and transfer that data from the controller to the view. If you want to edit and display customer info, take a look at this

Linq - reuse expression on child property

Not sure if what I am trying is possible or not, but I'd like to reuse a linq expression on an objects parent property.
With the given classes:
class Parent {
int Id { get; set; }
IList<Child> Children { get; set; }
string Name { get; set; }
}
class Child{
int Id { get; set; }
Parent Dad { get; set; }
string Name { get; set; }
}
If i then have a helper
Expression<Func<Parent,bool> ParentQuery() {
Expression<Func<Parent,bool> q = p => p.Name=="foo";
}
I then want to use this when querying data out for a child, along the lines of:
using(var context=new Entities.Context) {
var data=context.Child.Where(c => c.Name=="bar"
&& c.Dad.Where(ParentQuery));
}
I know I can do that on child collections:
using(var context=new Entities.Context) {
var data=context.Parent.Where(p => p.Name=="foo"
&& p.Childen.Where(childQuery));
}
but cant see any way to do this on a property that isnt a collection.
This is just a simplified example, actually the ParentQuery will be more complex and I want to avoid having this repeated in multiple places as rather than just having 2 layers I'll have closer to 5 or 6, but all of them will need to reference the parent query to ensure security.
If this isnt possible, my other thought was to somehow translate the ParentQuery expression to be of the given type so effectively:
p => p.Name=="foo";
turns into:
c => c.Dad.Name=="foo";
but using generics / some other form of query builder that allows this to retain the parent query and then just have to build a translator per child object that substitutes in the property route to the parent.
EDIT:
Following on from comments by #David morton
Initially that looks like I can just change from Expression to a delegate function and then call
.Where(ParentQuery()(c.Dad));
However I am using this in a wider repository pattern and cant see how I can use this with generics and predicate builders - I dont want to retrieve rows from the store and filter on the client (web server in this case). I have a generic get data method that takes in a base expression query. I then want to test to see if the supplied type implements ISecuredEntity and if it does append the securityQuery for the entity we are dealing with.
public static IList<T> GetData<T >(Expression<Func<T, bool>> query) {
IList<T> data=null;
var secQuery=RepositoryHelperers.GetScurityQuery<T>();
if(secQuery!=null) {
query.And(secQuery);
}
using(var context=new Entities.Context()) {
var d=context.GetGenericEntitySet<T>();
data=d.ToList();
}
return data;
}
ISecuredEntity:
public interface ISecuredEntity : IEntityBase {
Expression<Func<T, bool>> SecurityQuery<T>();
}
Example Entity:
public partial class ExampleEntity: ISecuredEntity {
public Expression<Func<T, bool>> SecurityQuery<T>() {
//get specific type expression and make generic
Type genType = typeof(Func<,>).MakeGenericType(typeof(ExampleEntity), typeof(bool));
var q = this.SecurityQuery(user);
return (Expression<Func<T, bool>>)Expression.Lambda(genType, q.Body, q.Parameters);
}
public Expression<Func<ExampleEntity, bool>> SecurityQuery() {
return e => e.OwnerId==currentUser.Id;
}
}
and repositoryHelpers:
internal static partial class RepositoryHelpers {
internal static Expression<Func<T, bool>> SecureQuery<T>() where T : new() {
var instanceOfT = new T();
if (typeof(Entities.ISecuredEntity).IsAssignableFrom(typeof(T))) {
return ((Entities.ISecuredEntity)instanceOfT).SecurityQuery<T>();
}
return null;
}
}
EDIT Here is the (eventual) solution
I ended up going back to using expressions, and using LinqKit Invoke. Note: for EF I also had to call .AsExpandable() on the entitySet
The key part is being able to call:
Product.SecureFunction(user).Invoke(pd.ParentProduct);
so that I can pass in the context into my parent query
My end classes look like:
public interface ISecureEntity {
Func<T,bool> SecureFunction<T>(UserAccount user);
}
public class Product : ISecureEntity {
public Expression<Func<T,bool>> SecureFunction<T>(UserAccount user) {
return SecureFunction(user) as Expression<Func<T,bool>>;
}
public static Expression<Func<Product,bool>> SecureFunction(UserAccount user) {
return f => f.OwnerId==user.AccountId;
}
public string Name { get;set; }
public string OwnerId { get;set; }
}
public class ProductDetail : ISecureEntity {
public Expression<Func<T,bool>> SecureFunction<T>(UserAccount user) {
return SecureFunction(user) as Expression<Func<T,bool>>;
}
public static Func<ProductDetail,bool> SecureFunction(UserAccount user) {
return pd => Product.SecureFunction(user).Invoke(pd.ParentProduct);
}
public int DetailId { get;set; }
public string DetailText { get;set; }
public Product ParentProduct { get;set; }
}
Usage:
public IList<T> GetData<T>() {
IList<T> data=null;
Expression<Func<T,bool>> query=GetSecurityQuery<T>();
using(var context=new Context()) {
var d=context.GetGenericEntitySet<T>().Where(query);
data=d.ToList();
}
return data;
}
private Expression<Func<T,bool>> GetSecurityQuery<T>() where T : new() {
var instanceOfT = new T();
if (typeof(Entities.ISecuredEntity).IsAssignableFrom(typeof(T))) {
return ((Entities.ISecuredEntity)instanceOfT).SecurityQuery<T>(GetCurrentUser());
}
return a => true; //returning a dummy query
}
}
Thanks for the help all.
You're overthinking it.
First, don't return an Expression<Func<Parent, bool>>, that'll require you to compile the expression. Return simply a Func<Parent, bool> instead.
Next, it's all in how you call it:
context.Children.Where(c => c.Name == "bar" && ParentQuery()(c.Dad));
context.Parents.Where(ParentQuery());

Resources