Update one object with another in LINQ - linq

I use LINQ to expose database objects to my application. Also in this application I get an object from my database called 'foo' like so.
public static Foo Get(int id)
{
MyDataContext db = new MyDataContext ();
Foo foo1 = (from f in db.Foos
where f.foo_id = id
select f).SingleOrDefault();
return foo1;
}
Now, if I change foo and want to update it without going through each field explicitly - I want to avoid this.
public static Foo Update(Foo foo)
{
MyDataContext db = new MyDataContext ();
Foo foo1 = (from f in db.Foos
where f.foo_id = foo.foo_id
select f).SingleOrDefault();
if(foo1 != null)
{
foo1.foo_nm = foo.foo_nm;
...
db.SubmitChanges();
}
}
Is there a way I can do something like in the entity framework:
foo1.UpdateVales(foo);

Create your own cloning method that copies all the properties you're interested in.
Alternatively you can use reflection to find all public properties and loop through them.
LINQ is no help here.

Here's a very simple (and also inefficient) extension function that can get you started (Make sure you import System.Reflection and System.Linq):
public static void GetDataFrom<T>(this T ObjToCopyTo, T ObjToCopyFrom) where T : class {
foreach (var property in ObjToCopyTo.GetType().GetProperties().Where(x => x.CanWrite))
property.SetValue(ObjToCopyTo, property.GetValue(ObjToCopyFrom, null), null);
}
You will probably find that you will have to put some special cases in for things like the primary keys, and may decide you do not want to copy every property exactly, but hopefully this shows the idea behind VVS's answer.
If you have linqpad installed you can play around with this idea with the following script:
void Main()
{
var foo = new Helper.Foo() {
field1 = "hi",
field2 = 5,
field3 = 3.14,
field4 = 'm'
};
var foo2 = new Helper.Foo();
foo.Dump("Foo Before");
foo2.Dump("Foo2 Before");
foo2.GetDataFrom(foo);
foo.Dump("Foo After");
foo2.Dump("Foo2 After");
}
public static class Helper {
public class Foo {
public string field1 { get; set; }
public int field2 { get; set; }
public double field3 { get; set; }
public char field4 { get; set; }
}
public static void GetDataFrom<T>(this T ObjToCopyTo, T ObjToCopyFrom) where T : class {
foreach (var property in ObjToCopyTo.GetType().GetProperties().Where(x => x.CanWrite))
property.SetValue(ObjToCopyTo, property.GetValue(ObjToCopyFrom, null), null);
}
}
I hope this helps!

I use automapper to avoid the heavy lifting to update the DB with MVC models, should work for mapping to the same object type and comes in handy for these sorts of coding styles.
After installing automapper ...
public ActionResult Example(TableModel model)
{
..
Mapper.CreateMap<TableModel, Table>();
Table myTable = new Table();
Mapper.Map(model, myTable);
...
}

Related

How to select multiple class properties in LINQ Expression?

If I have a class like this
`
class Person
{
public string First;
public string Last;
public bool IsMarried;
public int Age;
}`
Then how can I write a LINQ Expression where I could select properties of a Person. I want to do something like this (user can enter 1..n properties)
SelectData<Person>(x=>x.First, x.Last,x.Age);
What would be the input expression of my SelectData function ?
SelectData(Expression<Func<TEntity, List<string>>> selector); ?
EDIT
In my SelectData function I want to extract property names and then generate SELECT clause of my SQL Query dynamically.
SOLUTION
Ok, so what I have done is to have my SelectData as
public IEnumerable<TEntity> SelectData(Expression<Func<TEntity, object>> expression)
{
NewExpression body = (NewExpression)expression.Body;
List<string> columns = new List<string>();
foreach(var arg in body.Arguments)
{
var exp = (MemberExpression)arg;
columns.Add(exp.Member.Name);
}
//build query
And to use it I call it like this
ccc<Person>().SelectData(x => new { x.First, x.Last, x.Age });
Hopefully it would help someone who is looking :)
Thanks,
IY
I think it would be better to use delegates instead of Reflection. Apart from the fact that delegates will be faster, the compiler will complain if you try to fetch property values that do not exist. With reflection you won't find errors until run time.
Luckily there is already something like that. it is implemented as an extension function of IEnumerable, and it is called Select (irony intended)
I think you want something like this:
I have a sequence of Persons, and I want you to create a Linq
statement that returns per Person a new object that contains the
properties First and Last.
Or:
I have a sequence of Persns and I want you to create a Linq statement
that returns per Person a new object that contains Age, IsMarried,
whether it is an adult and to make it difficult: one Property called
Name which is a combination of First and Last
The function SelectData would be something like this:
IEnumerable<TResult> SelectData<TSource, TResult>(this IEnumerable<TSource> source,
Func<TSource, TResult> selector)
{
return source.Select(selector);
}
Usage:
problem 1: return per Person a new object that contains the
properties First and Last.
var result = Persons.SelectData(person => new
{
First = person.First,
Last = person.Last,
});
problem 2: return per Person a new object that contains Age, IsMarried, whether he is an adult and one Property called Name which is a combination
of First and Last
var result = Persons.SelectData(person => new
{
Age = person.Name,
IsMarried = person.IsMarried,
IsAdult = person.Age > 21,
Name = new
{
First = person.First,
Last = person.Last,
},
});
Well let's face it, your SelectData is nothing more than Enumerable.Select
You could of course create a function where you'd let the caller provide a list of properties he wants, but (1) that would limit his possibilities to design the end result and (2) it would be way more typing for him to call the function.
Instead of:
.Select(p => new
{
P1 = p.Property1,
P2 = p.Property2,
}
he would have to type something like
.SelectData(new List<Func<TSource, TResult>()
{
p => p.Property1, // first element of the property list
p -> p.Property2, // second element of the property list
}
You won't be able to name the returned properties, you won't be able to combine several properties into one:
.Select(p => p.First + p.Last)
And what would you gain by it?
Highly discouraged requirement!
You could achive similar result using Reflection and Extension Method
Model:
namespace ConsoleApplication2
{
class Person
{
public string First { get; set; }
public string Last { get; set; }
public bool IsMarried { get; set; }
public int Age { get; set; }
}
}
Service:
using System.Collections.Generic;
using System.Linq;
namespace Test
{
public static class Service
{
public static IQueryable<IQueryable<KeyValuePair<string, object>>> SelectData<T>(this IQueryable<T> queryable, string[] properties)
{
var queryResult = new List<IQueryable<KeyValuePair<string, object>>>();
foreach (T entity in queryable)
{
var entityProperties = new List<KeyValuePair<string, object>>();
foreach (string property in properties)
{
var value = typeof(T).GetProperty(property).GetValue(entity);
var entityProperty = new KeyValuePair<string, object>(property, value);
entityProperties.Add(entityProperty);
}
queryResult.Add(entityProperties.AsQueryable());
}
return queryResult.AsQueryable();
}
}
}
Usage:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Test
{
class Program
{
static void Main(string[] args)
{
var list = new List<Person>()
{
new Person()
{
Age = 18,
First = "test1",
IsMarried = false,
Last = "test2"
},
new Person()
{
Age = 40,
First = "test3",
IsMarried = true,
Last = "test4"
}
};
var queryableList = list.AsQueryable();
string[] properties = { "Age", "Last" };
var result = queryableList.SelectData(properties);
foreach (var element in result)
{
foreach (var property in element)
{
Console.WriteLine($"{property.Key}: {property.Value}");
}
}
Console.ReadKey();
}
}
}
Result:
Age: 18
Last: test2
Age: 40
Last: test4

AutoMapper doesn't map calculated field to scalar

I am trying to separate my MVC3 project into a proper DAL/Domain/ViewModel architecture, but I'm running into a problem with AutoMapper and mapping calculated fields from my domain to my view model.
Here's an example of what I'm trying to do:
Interface
public interface IRequirement
{
int Id { get; set; }
... bunch of others
public decimal PlanOct { get; set; }
public decimal PlanNov { get; set; }
public decimal PlanDec { get; set; }
... and so on
decimal PlanQ1 { get; }
... etc
decimal PlanYear { get; }
... repeat for ActualOct, ActualNov ... ActualQ1 ... ActualYear...
}
Domain Model
public class Requirement : IRequirement
{
public int Id { get; set; }
... bunch of others
public decimal PlanOct { get; set; }
public decimal PlanNov { get; set; }
public decimal PlanDec { get; set; }
... and so on
public decimal PlanQ1 { get { return PlanOct + PlanNov + PlanDec; } }
... etc
public decimal PlanYear { get { return PlanQ1 + PlanQ2 + PlanQ3 + PlanQ4; } }
... repeat for ActualOct, ActualNov ... ActualQ1 ... ActualYear...
}
There are also VarianceX properties, i.e. VarianceOct which is calculated as (PlanOct - ActualOct), etc.
My view model looks almost exactly the same, except instead of calculated fields it has the default getter/setter syntax, for example:
public decimal PlanQ1 { get; set; }
My AutoMapper config in Global.asax looks like this:
Mapper.CreateMap<Domain.Abstract.IRequirement, Models.Requirement.Details>();
This works fine on all properties except the calculated ones. None of my calculated fields (i.e. *Q1, *Q2, *Q3, *Q4, *Year, and all the Variance* fields) are actually mapped -- they all show up with the default value of 0.00.
I'm pretty stumped on this, and I'm also a novice at this and AutoMapper, so maybe I missed something. My intuition is that since the property signatures aren't identical (i.e. the domain object has only a non-default getter and no setter, while the view model has default getter and setter) then AutoMapper isn't picking it up. But I also did this:
Mapper.CreateMap<Domain.Abstract.IRequirement, Models.Requirement.Details>()
.ForMember(dest => dest.PlanQ1, opt => opt.MapFrom(src => src.PlanQ1);
And it still resolved to 0. I confirmed this in the debugger as well.
What am I doing wrong?
Thanks in advance.
EDIT 1
After following Wal's advice I ran the test and it worked, so I began working backwards one step at a time, first pasting in the Field1/Field2/Field3 parts into the interface/domain/view model classes and verifying it worked in my controller, then changing one thing at a time. What I found is that, since I am dealing with decimal types, if I hard-code in integer or double values then I get zero, but if I cast to a decimal or use a decimal literal then it works. But only if I manually set them, not if I pull the values from the database.
In other words, this works (i.e. PlanQ1 = 6):
var D = new Requirement { PlanOct = (decimal) 1.0, PlanNov = (decimal) 2.0, PlanDec = (decimal) 3.0 };
var V = Mapper.Map<IRequirement, Details>(D);
And this works:
var D = new Requirement { PlanOct = 1M, PlanNov = 2M, PlanDec = 3M };
var V = Mapper.Map<IRequirement, Details>(D);
But this does not (pulling a single domain object from a repository object, that in turn pulls from SQL Server using Entity Framework):
var D = requirementRepository.Requirement(5);
var V = Mapper.Map<IRequirement, Details>(D);
With the above all I get is 0 for PlanQ1 and PlanYear. I verified that PlanOct = 1, PlanNov = 2, and PlanDec = 3 in the domain object (D). I also verified that the type in all objects, including the EF generated object, is decimal, and the SQL Server type is decimal. I even tried mapping to a created view model, just to rule that out, and I still get 0 for PlanQ1 and PlanYear:
var D = requirementRepository.Requirement(5);
var V = new Details();
Mapper.Map<IRequirement, Details>(D, V);
is PlanQ1 a member of IRequirement ? you have implied it is by your last code snippet but if it isn't then you will get the behavior exactly as you describe.
Consider a simplied example of what you are doing:
public interface IFoo
{
string Field1 { get; set; }
string Field2 { get; set; }
//string Field3 { get; }
}
public class Foo1 : IFoo
{
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get { return Field1 + Field2; } }
}
public class Foo2
{
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
}
Note in this instance I have omitted Field3 from the interface; now when I run the following the mapping fails
[TestMethod]
public void Map()
{
Mapper.CreateMap<IFoo, Foo2>();
var foo1 = new Foo1() { Field1 = "field1", Field2 = "field2" };
var foo2 = new Foo2();
Mapper.Map(foo1, foo2);
Assert.AreEqual("field1field2", foo2.Field3);//fails, not mapped
}
So if I comment in Field3 from IFoo everything works again. Check this simplified example with your code.
Consider #Wal post, Try this Map,
Mapper.CreateMap<IFoo, Foo2>()
.ForMember(destination => destination.Field3, options => options.MapFrom(source => source.Field1 + source.Field2));
And
[TestMethod]
public void Map()
{
Mapper.CreateMap<IFoo, Foo2>()
.ForMember(destination => destination.Field3, options => options.MapFrom(source => source.Field1 + source.Field2));
var foo1 = new Foo1() { Field1 = "field1", Field2 = "field2" };
var foo2 = new Foo2();
Mapper.Map(foo1, foo2);
Assert.AreEqual("field1field2", foo2.Field3); // True
}
Just realized this was left unanswered so I wanted to close it out. Technically it is unanswered because I couldn't get Automapper to play nice in this scenario for some reason. What I wound up doing is going back and creating a couple of mapping methods inside my repository, one to map a single instance of the DAL object to the IRequirement object, and one to map a collection. Then in the repository instead of calling Mapper.Map I just call my custom mapping methods and it works perfectly.
I still don't understand why this doesn't work, but I've run into a few other classes where Automapper just throws up and I have to manually map at least one or two fields, though Automapper does take care of the rest in those cases.
I'm sure there's something about it I just don't see yet. But in any case, falling back to partial or fully manual mapping was my workaround.

Building a query (LINQ) with a sub-query

For simplicity sake lets assume I have the following two classes:
public class ComplexClass
{
public List<SubClass> SubClasses { get; set; }
public string Name { get; set; }
}
public class SubClass
{
public string Name { get; set; }
}
I have a List<ComplexClass> and I need to build a query based on some parameters.
It's an easy task if all I need to do is use the Name property of ComplexClass. Here's an example:
static IQueryable<ComplexClass> GetQuery(string someParameter, string someOtherParameter)
{
var query = list.AsQueryable();
if (!String.IsNullOrEmpty(someParameter))
query = query.Where(c => c.Name.StartsWith(someParameter));
if (!String.IsNullOrEmpty(someOtherParameter))
query = query.Where(c => c.Name.EndsWith(someOtherParameter));
return query;
}
Based on the parameters I have I can add more query elements. Of course the above example is simple, but the actual problem contains more parameters, and that number can grow.
Things aren't as simple if I want to find those ComplexClass instances which have SubClass instances which meet criteria based on parameters:
static IQueryable<ComplexClass> GetSubQuery(string someParameter, string someOtherParameter)
{
var query = list.AsQueryable();
if (!String.IsNullOrEmpty(someParameter))
if (!String.IsNullOrEmpty(someOtherParameter))
return query.Where(c => c.SubClasses.Where(sc => sc.Name.StartsWith(someParameter) && sc.Name.EndsWith(someOtherParameter)).Any());
else
return query.Where(c => c.SubClasses.Where(sc => sc.Name.StartsWith(someParameter)).Any());
else
if (!String.IsNullOrEmpty(someOtherParameter))
return query.Where(c => c.SubClasses.Where(sc => sc.Name.EndsWith(someOtherParameter)).Any());
else
return null;
}
I can no longer just add bits of the query based on each parameter, I now need to write the whole query in one go, and this means I need to check every combination of parameters, which is hardly ideal.
I suspect the key is to build an Expression class and create a lambda expression from that, but I'm not sure how to tackle the problem.
Any suggestions? :)
EDIT:
My initial idea was this:
static IQueryable<ComplexClass> GetSubQuery(string someParameter, string someOtherParameter)
{
var query = list.AsQueryable();
query = query.Where(c =>
{
var subQuery = c.SubClasses.AsQueryable();
if (!String.IsNullOrEmpty(someParameter))
subQuery = subQuery.Where(sc => sc.Name.StartsWith(someParameter));
if (!String.IsNullOrEmpty(someOtherParameter))
subQuery = subQuery.Where(sc => sc.Name.EndsWith(someOtherParameter));
return subQuery.Any();
});
return query;
}
This works in my small console test application as it's using LINQ to Objects. Unfortunately, I need to use Entity Framework and LINQ to Entities, which causes an implementation similar to the one above to throw a A lambda expression with a statement body cannot be converted to an expression tree error message.
I'm assuming that in you real-life code the SubClasses property is IQueryable<SubClass> rather than List<SubClass>?
If so, then your query building becomes easy:
static IQueryable<ComplexClass> GetSubQuery(
string someParameter, string someOtherParameter)
{
var query = list.AsQueryable();
if (!String.IsNullOrEmpty(someParameter))
query = query.Where(c => c.SubClasses
.Where(sc => sc.Name.StartsWith(someParameter)).Any());
if (!String.IsNullOrEmpty(someOtherParameter))
query = query.Where(c => c.SubClasses
.Where(sc => sc.Name.StartsWith(someOtherParameter)).Any());
return query;
}
Mixing IEnumerable<T> and IQueryable<T> using AsQueryable() is never a good idea.
I implemented my solution in a simple Console Project:
internal class Program
{
#region Constants and Fields
private static readonly List<ComplexClass> list = new List<ComplexClass>
{
new ComplexClass
{
Name = "complex",
SubClasses = new List<SubClass>
{
new SubClass
{
SubName = "foobar"
}
}
},
new ComplexClass
{
Name = "complex",
SubClasses = new List<SubClass>
{
new SubClass
{
SubName = "notfoobar"
}
}
}
};
#endregion
#region Public Methods
public static void Main(string[] args)
{
Console.WriteLine("foo / bar :");
GetSubQuery("foo", "bar");
Console.WriteLine();
Console.WriteLine("foo / null :");
GetSubQuery("foo", null);
Console.WriteLine();
Console.WriteLine("string.Empty / bar :");
GetSubQuery(string.Empty, "bar");
Console.WriteLine();
Console.WriteLine("maeh / bar :");
GetSubQuery("maeh", "bar");
Console.ReadKey();
}
#endregion
#region Methods
private static void GetSubQuery(string startsWith,
string endsWith)
{
var query = from item in list
let StartIsNull = string.IsNullOrEmpty(startsWith)
let EndIsNull = string.IsNullOrEmpty(endsWith)
where
(StartIsNull || item.SubClasses.Any(sc => sc.SubName.StartsWith(startsWith)))
&& (EndIsNull || item.SubClasses.Any(sc => sc.SubName.EndsWith(endsWith)))
select item;
foreach (var complexClass in query)
{
Console.WriteLine(complexClass.SubClasses.First().SubName);
}
}
#endregion
public class ComplexClass
{
#region Public Properties
public string Name { get; set; }
public List<SubClass> SubClasses { get; set; }
#endregion
}
public class SubClass
{
#region Public Properties
public string SubName { get; set; }
#endregion
}
}
The Console Output is:
foo / bar :
foobar
foo / null :
foobar
string.Empty / bar :
foobar
notfoobar
maeh / bar :

ef cf linq populate ignored property

I'm sure this has to have been asked before, but I couldn't find a good way to search on it.
I have a class like the following
public class Vendor
{
public int VendorId { get; set; }
public string Name { get; set; }
public int ProductCount { get; set; }
}
I have a configuration class setup like
public class VendorConfiguration : EntityTypeConfiguration<Vendor>
{
public VendorConfiguration()
{
Property(p => p.Name).IsRequired().HasMaxLength(128);
Ignore(v => v.ProductCount);
}
}
Here is the query i use to grab the vendors.
public Vendor[] GetVendors()
{
using (var db = new UbidContext())
{
var query = (from vendor in db.Vendors
select vendor);
return query.ToArray();
}
}
How could I populate ProductCount with a subquery that would look similar to
ProductCount = (from vend in db.VendorProducts
where vend.VendorId == id
select vend).Count()
Is there a way I can add that to the main query, so I'm only making 1 call to the db?
Thanks,
Andrew
I would try it this way:
public Vendor[] GetVendors()
{
using (var db = new UbidContext())
{
var query = from vendor in db.Vendors
join vp in db.VendorProducts
on vendor.VendorId equals vp.VendorId
into vendorProducts
select new
{
Vendor = vendor,
ProductCount = vendorProducts.Count()
};
foreach (var item in query)
item.Vendor.ProductCount = item.ProductCount;
return query.Select(a => a.Vendor).ToArray();
}
}
Problem is that you must project into a non-entity type (anonymous in the example above) and then copy the projected ProductCount value into the projected Vendor item by item before you return it.

Using structuremap getinstance in linq statement with initializer values

I'm not sure how to ask this, but I want to create a new object in a linq statement, and initialize it's values. Since I have to use StructureMap's GetInstance method to get an instance of the object, I don't think this is possible. Am I wrong? And before we get off-topic, I realize I could probably create a constructor that takes the values I want to use, but I want to know if there's any way that I can do it with initializers and structuremap. I'm really weak on structuremap, and for all I know, there may be a simple way I'm just missing...
Thanks for any thoughts.
//basically, I'm creating a new object when I don't have an existing one for the groupid
//conceptually, this is adding users to the selected groups if they don't already belong
from g in GroupIDs where !OriginalGroups.Exists(ug => ug.SecurityGroupID == g) select StructureMap.ObjectFactory.GetInstance() {//initialize values of usertosecuritygroup};
//this is how I would do it if I wasn't relying on DI.
from g in GroupIDs where !OriginalGroups.Exists(ug => ug.SecurityGroupID == g) select new UserToGroup {UserID = UserID, GroupID = g};
If you start using method chains rather than LINQ expressions you could do something like this:
[TestFixture]
public class so_1
{
public class UserToGroup
{
public int UserId { get; set; }
public int GroupId { get; set; }
}
[Test]
public void TEST()
{
var container = new Container();
var groupIds = new int[] { 1,2,3,4,5};
var originaGroups = new int[] { 4, 5 };
var result = groupIds.Intersect(originaGroups).Select(group =>
{
var myClass = container.GetInstance<UserToGroup>();
myClass.GroupId = group;
return myClass;
});
result.First().GroupId.ShouldEqual(4);
result.Skip(1).First().GroupId.ShouldEqual(5);
}
}

Resources