how to group by ef entity with two properties - c#

I have for example entity with multiple properties 'myEntity' and I want to Group By 'Age' and 'sex
public class myEntity
{
public int Id{get; set;}
public string FirstName{get; set;}
public string LastName{get; set;}
public int sex{get; set;}
public int Age{get; set;}
}
I try the following query but I get error
var resultTable= dbContext.CashVacs.GroupBy(g => g.sex, g => g.age);

To expand on #MikeMozhaev's comment, the GroupBy method only takes one property which it uses for grouping.
In your case, you need to wrap the two properties you want to group by onto one. The simplest way to do this is to use a tuple...
var resultTable = dbContext.CashVacs.GroupBy(g => new {g.sex, g.Age});
P.S. All credit to #MikeMozhaev who answered first, I'm trying to add some explanation so the OP can (hopefully) understand why that comment answers the question. If #MikeMozhaev wants to post this as an answer, I would be happy for the OP to accept that rather than mine.

Related

Comparing Collections Fluent Assertions Should All Be Equivalent To Synonyms

I'm using Fluent Assertions to Validate to different test Objects
public class DTO
{
public int Key {get; set;}
public string Code { get; set; }
}
public class KeyDTO
{
public int Id {get; set;}
public string Code { get; set; }
}
Note: this is not an exact replica of the code there are more field in the Original DTO but they're not necessary to explain the problems
I'm creating a function to assert that they are equal I'm trying use fluent assertions to do so. I Can't figure out a way to say that the Id Maps To the Key.
public void AssertDTOsAreEqual( List<DTO> orderedDTOs, List<KeyDTO> orderedKeys)
{
orderedDTOs.ShouldAllBeEquivalentTo(orderedKeys, o => o/*??*/)
}
Note: I Know as an alternative I can do this by zipping the ordered collections and comparing each property, but for more lengthy DTO's this would be trouble doing compairisons for each property.
Does anyone know of a way to map different properties in the ShouldAllBeEquivalentTo. Or Perhaps a better way to do this in general?
Unfortunately not yet. But this my personal number one on my list of features to add. I hope to get some time soon.
subjectCollection.Should().AllBeEquivalentTo(expected) has now been implemented in FluentAssertions:
https://fluentassertions.com/documentation/#collections-and-dictionaries
My apologies, I misread the question. The best I can come up with in the current version of FluentAssertions is to project the expected collection using Linq's .Select and compare to the new objects:
subjectCollection.Should().BeEquivalentTo(expectedCollection.Select(o => new { Id = o.Key }));

MVC ViewModel EntityFrameWork ICollection,IEnumerable virtual Class

I have gone through a lot of documents and found several ways of trying to make a CreateViewModel.
I want to know what does ICollection Does.
public Payment{
public int ID {get; set;}
public string Details {get; set;}
public virtual ICollection<Expense> Expenses {get; set;}
}
public Expense{
public int ID {get; set;}
public string MyDetails {get; set;}
}
So I guess in my View, I can Use just the plain class as virtual to make a Create Method. But if I want to use ViewModel to make a view with 2 or more DataModels for Creation. How will I go with that. Cause I guess I can always just make a
public virtual Payment payments {get; set;}
public virtual Expense expenses {get; set;}
But I am trying to ready this for Dynamically Having a Add Button Generating an Expense Details Input.
Not to mention, the IEnumerable as well, but I guess this needs an ID more suitable for Editing and Details for what I understand.
All you need is a PaymentViewModel class, where you'll use List<Expense> instead of ICollection<Expense>:
public class PaymentViewModel
{
// ID property unnecessary here because it doesn't need
// to be posted from the form
public string Details { get; set; }
// You may want to use something like `List<ExpenseViewModel>`
// based on your needs
public List<Expense> Expenses { get; set; }
}
With that, you add additional expense records to your form by making sure the input names are in the format of Expenses[N].MyDetails, where N is the index. Whatever JavaScript solution you use to add additional expense records to the form should create these inputs with properly indexed names. This would be a good place to use a JavaScript templating solution, or something that handles data-binding like Knockout.
For editing existing expenses, should you have the need, you just generate the fields like with any collection, but you need to use a for loop rather than the more traditional foreach:
#for (var i = 0; i < Model.Expenses.Count(); i++)
{
#Html.EditorFor(m => m.Expenses[i].MyDetails)
}
As a side note, since you asked, ICollection<T> is the required type for entity navigation properties with Entity Framework. These reasons are very low level, but has to do with the way Entity Framework handles one-to-many and many-to-many relationships at an object level and issues such as lazy loading. However, ICollection<T> doesn't work for actually submitting items through an HTML form, due mostly to the fact that it's not indexable. That's why a view model is so important in this scenario.

RavenDB SelectMany alternative

Am building a Photo gallery using Nancy and RavenDB
I have my model classes as below:
[JsonObject(IsReference=true)]
public class Album
{
public Album()
{
this.Photos = new List<Photo>();
this.Tags = new List<String>();
}
public String Id {get; set;}
public String Name {get; set;}
public String Path {get; set;}
public DateTime ModifiedDate{get; set;}
public IList<String> Tags {get; set;}
public IList<Photo> Photos {get; set;}
}
public class Photo
{
public String Id {get; set;}
public String Name {get; set;}
public String Path {get; set;}
public IList<String> Tags {get; set;}
public Album Album {get; set;}
public DateTime ModifiedDate{get; set;}
public bool IsPrivate{get; set;}
}
And my attempt at map reduce index on Photo->Tags:
public class TaggedPhotosIndex:AbstractIndexCreationTask<Album, TaggedPhotos>
{
public TaggedPhotosIndex()
{
Map = albums =>
from a in albums
from p in a.Photos
from t in p.Tags
select new TaggedPhotos
{
Tag = t,
PhotoIds = new List<String> {p.Id}
};
Reduce = results =>
from result in results
group result by result.Tag into agg
select new TaggedPhotos
{
Tag = agg.Key,
PhotoIds = agg.SelectMany(a => a.PhotoIds).ToList()
};
}
}
public class TaggedPhotos
{
public String Tag {get; set;}
public IList<String> PhotoIds {get; set;}
}
Here is what I want to achieve:
Given an array of tags, I want to get all the Photo objects that have atleast one matching tag.
RavenDB doesn't allow SelectMany in the query and am out of ideas.
Found a solution (using LuceneQuery # Workaround for selectmany in ravendb using client api) , but looking forward for any other alternatives.
There are some issues with your document structure that are going to make your query difficult.
Queries are designed to return whole documents. You are asking for a partial result from the document. That can be done, but only if you store all fields in the index and project the results from there. You give up the ACID guarantees of the document store, which is one of RavenDB's strongest features.
You have a reference from Photo back to Album which would normally be embedded, causing a circular reference, except you are setting [JsonObject(IsReference=true)] to avoid that. This may work for basic serialization within a single document, but it is meaningless when it comes to referencing a whole document back from a projected index value. You've set up your own "chicken & egg" problem.
You still are missing basic functionality one would expect from this problem domain. Specifically, you should be able to load a single photo without having to load the whole album.
I strongly suggest that you put photos in their own documents. Then you can have much simpler indexes and avoid the circular references. In DDD terms, both Photo and Album are aggregates. And a DDD aggregate == a RavenDB document. You are currently modeling the Photo as an entity that is not an aggregate, but then you are asking for operations that one would only do against an aggregate - like the search.
If you were asking only "give me all albums that contain a photo tagged with one of these tags", then you would be ok. But you're not asking for the albums, you're asking for the photos.
Assuming you did model it that way, Brett's answer is close - but has some extraneous stuff. Here is a unit test showing a full implementation. Posting on gist since it does not directly address the original question. https://gist.github.com/4499724
This one took me a while but I verified the solution below is working.
First, modify your Index and index result as shown below.
public class TaggedPhotosIndex:AbstractIndexCreationTask<Photo, TaggedPhotos>
{
public TaggedPhotosIndex()
{
Map = photos =>
from p in Photos
from t in p.Tags
select new TaggedPhotos
{
Tag = t,
PhotoId = p.Id
};
}
}
public class TaggedPhotos
{
public string Tag {get; set;}
public string PhotoId {get; set;}
}
Now that the index is created, here is how you query against it to get your photos.
var tagsToSearch = new List<string>(){"test1", "test2", "test3"};
var photoIds = documentSession.Query<TaggedPhotos, TaggedPhotoIndex>()
.Customize(x => x.Include<Photo>(p => p.Id))
.Where(x => x.Tag.In(tagsToSearch))
.Select(x => x.PhotoId)
.Distinct()
.ToArray();
// This doesn't actually make a second call as the photos are already loaded
// in the document session
var photos = documentSession.Load<Photo>(photoIds);
Based on the requirement
Here is what I want to achieve:
Given an array of tags, I want to get all the Photo objects that have
at least one matching tag.
I didn't see how album really tied into it all

Entity Framework: Select all entities whose sub entities have a certain flag set

This should be an easy to answer question, though I can't really figure it out.
Here is the situation:
I use entity framework 4.1 as ORM using Code First. I have defined a pretty complex object model and everything works well so far.
Part of my model looks like this (left unimportant parts out for sakes of clarity):
public class Tier1
{
public virtual ICollection<Tier2> t2 {get; set;}
}
public Class Tier2
{
public virtual Tier3 t3 {get; set;}
}
public Class Tier3
{
public bool isActive
}
How can I formulate my statement in order to retrieve tier1 elements including only tier3 entities that have isActive set to true?
context.Tier1s.Where(???)
I'm assuming tier2 has only one tier3 yeah? It seems that way in your code. If so try this:
var myTiers = context.Tier1s
.Where(tier => tier.t2.Any(tier2 => tier2.t3.isActive))
.ToList();

Issues with Dynamic Search Expressions in EF

I currently am using a data structures similar to the following:
public class Individual
{
//Other properties omitted for brevity sake
public List<IndividualName> IndividualNames {get; set;}
}
and
public class IndividualName
{
public string FamilyName {get; set;}
public string GivenName {get; set;}
public string MiddleName {get; set;}
}
I am attempting to use some Dynamic search expressions to pass from my presentation layer to repository level (to actually apply the search).
However, I have run into some issues due to the fact that an Individual can have 1-M Individual Names, and I am trying to use LINQ to grab all of an Individual's IndividualNames so they can be queried.
For example's sake - this is what the expression currently looks like:
searchExpressions.Add(new SearchExpression("Individual
.IndividualNames
.Select(GivenName)
.FirstOrDefault()"
, ComparisonOperator.Contains, "Test");
This will currently only determine if the GivenName in the first IndividualName instance Contains "Test". The above works as it should - however I am a bit stuck in terms of how I would be able to determine if Any of the IndividualNames contained the string.
Any help would be appreciated - as I have tried several things without any luck.
I think you would be looking for....
searchExpressions.Add(new SearchExpression("Individual
.IndividualNames
.Select(GivenName)",
ComparisonOperator.Contains, "Test");
You will also need to add a Contains Aggregate Method to the Dynamic Linq library. How to do this can be found here.
http://blog.walteralmeida.com/2010/05/advanced-linq-dynamic-linq-library-add-support-for-contains-extension-.html
im not sure this is aplicable in your case, but maybe this lambda?
Individual.IndividualNames.Where(x => x.GivenName == "Test")

Categories

Resources