Changing values of an object in a LINQ-statement - linq

I want to add some calculated properties to an EntityObject without loosing the possibility of querying it agains the database.
I created a partial class and added the fields I need in the object. Than I wrote a static function "AttachProperties" that should somehow add some calculated values. I cannot do this on clientside, since several other functions attach some filter-conditions to the query.
The functions should look like this:
return query.Select(o =>
{
o.HasCalculatedProperties = true;
o.Value = 2;
return o;
});
In my case the calculated value depends on several lookups and is not just a simple "2". This sample works with an IEnumerable but, of course, not with an IQueryable
I first created a new class with the EntityObject as property and added the other necessary fields but now I need this extended class to be of the same basetype.

First, in my opinion changing objects in a Select() is a bad idea, because it makes something else happen (state change) than the method name suggests (projection), which is always a recipe for trouble. Linq is rooted in a functional programming (stateless) paradigm, so this kind of usage is just not expected.
But you can extend your class with methods that return a calculation result, like:
partial class EntityObject
{
public int GetValue()
{
return this.MappedProp1 * this.MappedProp2;
}
}
It is a bit hard to tell from your question whether this will work for you. If generating a calculated value involves more than a simple calculation from an object's own properties it may be better to leave your entities alone and create a services that return calculation results from an object graph.

Try something like this:
return from o in collection
select new O()
{
OtherProperty = o.OtherProperty,
HasCalculatedProperties = true,
Value = 2
};
This will create a copy of the original object with the changes you require and avoid all the messiness that come with modifying an entity in a select clause.

Related

Using LINQ to change values in collection

I think I'm not undertanding LINQ well. I want to do:
foreach (MyObjetc myObject in myObjectCollection)
{
myObjet.MyProperty = newValue
}
Just change all values for a property in all elements of my collection.
Using LINQ wouldn't be this way?
myObjectCollection.Select(myObject => myObject.MyProperty = newValue)
It doesn't work. The property value is not changed. Why?
Edit:
Sorry, guys. Certainly, foreach is the right way. But,in my case, I must repeat the foreach in many collections, and I didn't want to repeat the loop. So, finally, I have found an 'inermediate' solution, the 'foreach' method, just similar to the 'Select':
myObjectCollection.ForEach(myObject => myObject.MyProperty = newValue)
Anyway may be it's not as clear as the more simple:
foreach (MyObjetc myObject in myObjectCollection) myObjet.MyProperty = newValue;
First off, this is not a good idea. See below for arguments against it.
It doesn't work. The property value is not changed. Why?
It doesn't work because Select() doesn't actually iterate through the collection until you enumerate it's results, and it requires an expression that evaluates to a value.
If you make your expression return a value, and add something that will fully evaluate the query, such as ToList(), to the end, then it will "work", ie:
myObjectCollection.Select(myObject => { myObject.MyProperty = newValue; return myObject;}).ToList();
That being said, ToList() has some disadvantages - mainly, it's doing a lot of extra work (to create a List<T>) that's not needed, which adds a large cost. Avoiding it would require enumerating the collection:
foreach(var obj in myObjectCollection.Select(myObject => { myObject.MyProperty = newValue; return myObject; }))
{ }
Again, I wouldn't recommend this. At this point, the Select option is far uglier, more typing, etc. It's also a violation of the expectations involved with LINQ - LINQ is about querying, which suggests there shouldn't be side effects when using LINQ, and the entire purpose here is to create side effects.
But then, at this point, you're better off (with less typing) doing it the "clear" way:
foreach (var obj in myObjectCollection)
{
obj.MyProperty = newValue;
}
This is shorter, very clear in its intent, and very clean.
Note that you can add a ForEach<T> extension method which performs an action on each object, but I would still recommend avoiding that. Eric Lippert wrote a great blog post about the subject that is worth a read: "foreach" vs "ForEach".
As sircodesalot mentioned, you can't use linq to do something like that. Remember that linq is a querying language, which means all you can do is query it. Doing changes must be done in other logic.
What you could do, if you don't want to do it the first way and if your collection is a list already (but not an IEnumerable) you can use the ForEach extension method in linq to do what you're asking.
One other point I should mention is that the Select method does a projection of some specific information to return to an IEnumerable. So, if you wanted to grab only a specific property from a collection you would use that. That's all it does.

How to combine collection of linq queries into a single sql request

Thanks for checking this out.
My situation is that I have a system where the user can create custom filtered views which I build into a linq query on the request. On the interface they want to see the counts of all the views they have created; pretty straight forward. I'm familiar with combining multiple queries into a single call but in this case I don't know how many queries I have initially.
Does anyone know of a technique where this loop combines the count queries into a single query that I can then execute with a ToList() or FirstOrDefault()?
//TODO Performance this isn't good...
foreach (IMeetingViewDetail view in currentViews)
{
view.RecordCount = GetViewSpecificQuery(view.CustomFilters).Count();
}
Here is an example of multiple queries combined as I'm referring to. This is two queries which I then combine into an anonymous projection resulting in a single request to the sql server.
IQueryable<EventType> eventTypes = _eventTypeService.GetRecords().AreActive<EventType>();
IQueryable<EventPreferredSetup> preferredSetupTypes = _eventPreferredSetupService.GetRecords().AreActive<EventPreferredSetup>();
var options = someBaseQuery.Select(x => new
{
EventTypes = eventTypes.AsEnumerable(),
PreferredSetupTypes = preferredSetupTypes.AsEnumerable()
}).FirstOrDefault();
Well, for performance considerations, I would change the interface from IEnumerable<T> to a collection that has a Count property. Both IList<T> and ICollection<T> have a count property.
This way, the collection object is keeping track of its size and you just need to read it.
If you really wanted to avoid the loop, you could redefine the RecordCount to be a lazy loaded integer that calls GetViewSpecificQuery to get the count once.
private int? _recordCount = null;
public int RecordCount
{
get
{
if (_recordCount == null)
_recordCount = GetViewSpecificQuery(view.CustomFilters).Count;
return _recordCount.Value;
}
}

Grails: Constraints: Database to allow nulls, but forms may not be blank

I have a domain object called OurCompany and I'd like to be able to deliberately insert a row mostly full of nulls. When a user fills in a form though, I'd like to validate it and not allow blanks.
class OurCompany {
static constraints = {
enterpriseName blank:false, nullable:true
}
String enterpriseName
static belongsTo = [measurement:Measurement]
}
When I create the empty row in the database, I turn off validation and it works fine.
ourCompany = new OurCompany();
measurement.addToOurCompany(ourCompany).save(validate:false);
Later, when I update the row, the validation is ignored and the record saves even though there is a null / blank value.
def ourCompany = loadOrCreateOurCompany();
def industrySectors = loadIndustrySectors();
bindData (ourCompany, params)
ourCompany.validate()
if (ourCompany.hasErrors()) {
ourCompany.errors.allErrors.each {
println(it)
}
} else {
ourCompany.save();
}
How do I tell grails that I'd like the DATABASE to accept nulls, but when validating, not allow nulls or blanks?
That's what Command Objects are for
The solution (so far) REALLY ugly. It seems that there is no way to make a grails domain property BOTH nullable and have a CONSTRAINT. The only way to do it is to use a Command Object to do the validation against. In my opinion, it's really quite a painful solution and a rather inelegant, poorly documented methodology. This has been my most unpleasant grails experience.

Grails many to many with 3 classes: sorting by the number of relationships

Let's say we have 3 domain classes: 2 classes related with each other through a 3rd class.
Ok, some code:
class A {
String subject
String description
static hasMany = [cs: C]
static transients = ['numberOfCs']
Long getNumberOfCs() {
return cs.size()
}
}
class B {
String title
}
class C {
A objectA
B objectB
static belongsTo = [a: A]
}
Pretty clear? I hope so. This work perfectly with my domain.
You can see the transient property numberOfCs, which is used to calculate the number of C instances related to my A object. And it works just fine.
The problem: listing all my A objects, I want to sort them by the number of relationships with C objects, but the transient property numberOfCs cannot be used for the scope.
How can I handle the situation? How can I tell GORM to sort the As list by numberOfCs as it would be a regular (non transient) field?
Thanks in advance.
I'm not sure that Grails' criteria do support this, as you need both to select the A object itself and aggregate by a child objects (C). That means grouping by all the A's fields, which is not done automatically.
If you only need some fields from A, you can group by them:
def instances = A.withCriteria {
projections {
groupProperty('subject')
count('cs', 'cCount')
}
order 'cCount'
}
otherwise you'll need to retrieve only ids and make a second query, like in this question.
Another way is to use derived properties like described here (not sure it will work though):
class A {
static mapping = {
numberOfCs formula: 'select count(*) from C where c.b_id = id'
}
}
I wouldn't consider your Problem GORM related but rather general Hibernate or even SQL related.
Take a look at the HQL Docu they are a lot of examples.
check the following HQL this pretty close what you are asking.
select mySortedAs from A mySortedAs left join mySortedAs.cs myCsOfA order by
count(myCsOfA)
I think I saw somewhere that you also can do something like this myCsOfA.length or myCsOfA.size

help with expression for nHibernate linq provider extension

I'm working on a custom linq extension for nHibernate by extending the BaseHqlGeneratorForMethod. The technique is documented here:
http://fabiomaulo.blogspot.com/2010/07/nhibernate-linq-provider-extension.html
I've had success with implementing these for various types of operations, but I must say - converting a simple linq expression to its full expression tree is not easy! I'm stuck on one now.
For this example, I have three entities. Employee, Group, and EmployeeGroup. The EmployeeGroup class sets up a many-to-many relationship between Employee and Group. I must specifically create the intermediate class because there are additional properties to track like specific permissions each employee has in each group. So there are two one-to-many relationships, rather than an nHibernate many-to-many relationship.
Now say I want to get all groups that contain a specific employee. I can write this query:
var groups = session.Query<Group>()
.Where(g => g.EmployeeGroups.Any(eg => eg.Employee == employee));
This works fine, but it's a lot to type. I'd much rather be able to do this:
var groups = session.Query<Group>().Where(g => g.HasEmployee(employee));
I start by creating an extension method like so:
public static bool HasEmployee(this Group group, Employee employee)
{
return group.EmployeeGroups.Any(eg => eg.Employee == employee);
}
This works when querying a local list of groups, but not against the nHibernate session. For that, I have to also create a linq extension and register it. Just like in the article (linked above), I create a GroupHasEmployeeGenerator class that extends BaseHqlGeneratorForMethod. I set its .SupportedMethods property to reference my HasEmployee extension method.
Where I get lost is in the override to BuildHql. The expression to build gets complicated pretty fast. I figure since I'm replacing the .Any clause - a good place to start is with the source for the built-in AnyHqlGenerator class. But that doesn't take into account that the source is a property of the original element, and it also doesn't take into account that I don't have a lambda expression to represent the where clause. I need to build these parts manually.
There's no point in posting my attempts so far, as they've all be quite far from anything that would work.
Will someone please help me convert this simple expression into the approprate set of methods for the BuildHql method override?
If there is any better documentation out there for this, please let me know. Thanks.
I know this question is a year old, but I ran into a very similar issue when implementing BaseHqlGeneratorForMethod today.
The input to BuildHql contains a collection of System.Linq.Expressions.Expression arguments that are passed to your extension method. Using these arguments, you can build an expression tree that represents the implementation of your extension method. If the resulting expression is something NHibernate.Linq supports, then you can transform that expression to a subtree of Hql using the provided IHqlExpressionVisitor.
In your example:
public static bool HasEmployee(this Group group, Employee employee)
{
return group.EmployeeGroups.Any(eg => eg.Employee == employee);
}
This would become something similar to this:
public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
var AnyMethod = EnumerableHelper.GetMethod("Any", new[] {typeof(IEnumerable<EmployeeGroup>), typeof(Func<EmployeeGroup, bool>)}, new[] {typeof(EmployeeGroup)});
var EmployeeGroupsProperty = ReflectionHelper.GetProperty<Group>(g => g.EmployeeGroups);
var EmployeeProperty = ReflectionHelper.GetProperty<EmployeeGroup>(eg => eg.Employee);
var EmployeeGroupParameter = Expression.Parameter(typeof(EmployeeGroup));
var EmployeeGroupPredicate = Expression.Lambda(Expression.Equal(Expression.MakeMemberAccess(EmployeeGroupParameter, EmployeeProperty), arguments[1]), EmployeeGroupParameter);
var CallExpression = Expression.Call(AnyMethod, Expression.MakeMemberAccess(arguments[0], EmployeeGroupsProperty), EmployeeGroupPredicate);
return visitor.Visit(CallExpression);
}
I can't really test this specific example, but the same approach worked for me when providing support for my own extension method.

Resources