Issues with Dynamic Search Expressions in EF - c#

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")

Related

how to group by ef entity with two properties

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.

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 }));

Add OData to Web API 2 without coupling clients and server

I want to add OData syntax for querying my application's data. I don't want to fully implement ODataController, but have ApiController and implement one GET action that will support OData queries, as described here: Supporting OData Query Options in ASP.NET Web API 2
Example of what I want to have:
public class LetterEntity
{
public int Id {get; set;}
public string Title {get; set;}
public string Content {get; set;}
public string Source {get; set;}
public DateTime SendingTime {get; set;}
public string AnotherWierdString {get; set;
...
}
public class LetterDTO
{
public int Id {get; set;}
public string Title {get; set;}
public string LetterContent {get; set;}
public string Source {get; set;}
public DateTime SendingTime {get; set;}
}
public class LetterInsideFolderDTO
{
public string Title {get; set;}
public string Source {get; set;}
}
public class LettersController : ApiController
{
// Is there a way to do something like the following?:
[HttpGet]
[Route("api/letters")]
[EnableQuery]
public IQueryable<LetterInsideFolderDTO> Get(ODataQueryOptions<LetterDTO> query)
{
IQueryable<Letter> letters = db.Letters;
var queryOnEntites = // Convert the query to work on the entities somehow? - This is where I need help!!
var afterQuery = query.ApplyTo(letters)
IQueryable<LetterInsideFolderDTO> dtos = afterQuery.ProjectTo<LetterInsideFolderDTO>(afterQuery)
return dtos;
}
}
Because of the fact that at the moment I take Entity model directly in the clients query, there is a strong coupling between clients and server.
For example if i want to query and get all the letters that has "abc" inside the Content field, I need to route to the following:
api/letters/?$filter=contains(Content,'abc')
If tomorrow I decide to change that property from "Content" to "LetterContent" all clients code will be broken.
How can I surpass it?
I have not tried it. This and this can help you to map the query url to actual controller by using router map and controller selector where you can map LetterDto to LetterEntity
This will work for Entity Framework (not sure for Nhibrenate but probably will) and will do a real SQL query not in memory filtering.
var queryOnEntites = db.Letters.Select(l=>new LetterDTO{Id =l.Id ... });
var afterQuery = query.ApplyTo(queryOnEntites);
But you shouldn't use DTOs with odata if you want to make some properties private to the API use builder.EntitySet<T1>("TEndpoint").EntityType.Ignore(o => o.SomeProp);
Now if you don't want the whole LetterEntity sent to client you have the $select=Id,... option for this purpose.
If you don't setup
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: null,
model: builder.GetEdmModel());
you don't have an Odata endpoint and $metadata won't be available.
I haven't tested it but this way I don't think the client libraries(.net,java,js...) would work and you will have to make raw ajax requests to get the data.
ODataQueryOptions<> and translate it to
ODataQueryOptions<>
You can't do this. ProjectTo(AutoMapper) function dose the same thing as .Select(l=>new LetterDTO{Id =l.Id ... }); but you will have problems with this. This all is dependent on your back end since IQueryable is not the same as IEnumerable.
http://blog.ploeh.dk/2012/03/26/IQueryableTisTightCoupling/
This all depends on what level of LINQ your back end provides (NHibrenate tends to be worse then EF, and if you are using Mongo, Elastic, Cassandra... who knows what might go wrong when you use AutoMapper)
If tomorrow I decide to change that property from "Content" to
"LetterContent" all clients code will be broken.
You can setup Name property on an Entity set with oData. Remember Odata is data access level not BL. You should treat it the same way as changing SQL column name in the database.
Instead of exposing your entity models directly, create ViewModels corresponding to each entity model. They are nothing but simple classes having same or only required properties which we want to be exposed to the outer world. Having implemented this way, your entity model properties may change but ViewModels can remain unchanged. You are also addressing the security aspect of not exposing every property of your entity to end clients.
Mapping between entity model and ViewModel has to be done by yourself or by an object-object mapper like AutoMapper.

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.

Using get/set asp.net c# theres too many properties

I am use to creating a properties class where I would include all my fields and have to write all the get/set properties then have another Database class where i would make all my database calls.
Properties Class
private int _intCard
public int IntCard
{
set { _intcard = value;}
}
Constructor here
Right now this does not feel like the right approach as I have over 120 properties that I will be dealing with and seems really time consuming to have to write each one of those properties out. I will need to add validation to some of the properties is my reason for choosing this way, i could validate it in the set method. Can anyone suggest an alternative way that I could look into to complete the same result.
********************---------------*******************
So giving the comments I understand my design is flawed that is what I figured coming into this question. I have an idea on how to fix this but do not know if it is the correct way to approach this. I searched for Object Design Principles and read up on that but will need more time to grasp what it is teaching me. For now I would like to know if this approach is the correct way
I am keeping track of applicants name,address,phone,faxnumber,cellphone,altphone,altaddress, same for spouse, and then children, references, company information.....and so on
I am not going to lie I do not understand abstract classes yet in order to implement this if that is the approach I should take I will take more time to learn that but for now was hoping this would be suitable.
Property classes would be as followed
applicant.cs, applicantspouse.cs, applicantcontactinfo.cs, appreferences.cs......
Is this along the lines of what I should be doing?
Thanks again
I can't help thinking your object modelling isn't right here. If you have a class with 120 properties then you've not divided up that object into separate roles/responsibilities etc. I would look at increasing (dramatically) the number of classes you're creating, and that way your solution becomes more manageable.
That won't reduce the number of properties that you have to handle. It may be worth considering immutable objects (do you need to set these properties beyond during construction?), and/or the use of the Builder pattern to aid construction.
Finally, do you need to expose these properties ? A key part of OO is telling objects to do things for you, rather than getting their contents and doing things for them. If you can tell an object to do something for you, you quite likely don't need to expose their (internal) fields.
By reading the comments it looks like you need at least two classes Person, Address something like:
public class Person
{
Guid Id {get; set;}
string Name {get; set;}
// ad infinitum the truely unique things that relate to an Individual
Address BusinessAddress {get; set;}
Address HomeAddress {get; set;}
Person Spouse {get; set;}
}
public class Address
{
Guid Id {get; set;}
Line1 {get; set;}
// ad infinitum all the truly unique things that relate to an address
}
The above is essentially pseudo-code and shouldn't be read as "This is exactly how to do it", I haven't for instance stated whether the properties are private/public/protected or indeed provided a constructor.
But it does show how you can use other classes as properties and in the case of "Spouse" create quite rich and deep object Hierarchies (Spouse could contain addresses and potentially another spouse - circular reference ahoy!) which can be populated and used to make code more readable and separate out the responsibility of the code to encapsulate a "concept/entity/domain" into a single unit who's job it is to be "that specific thing". Probably worth looking at OOP concepts like encapsulation, inheritance and so on (basically the four tenets of OO) here to get a feel for what an object should represent, this link has a brief intro and should help you in deciding how to break out the classes and construct more useful objects.
http://codebetter.com/raymondlewallen/2005/07/19/4-major-principles-of-object-oriented-programming/
In modern c# versions there's a super compact sintax for properties:
public class Properties {
public int IntCard { get; set; }
}
Here c# handles the private variable for you, this way you can avoid a lot of keystrokes. For validation you can use Data Annotations. More info here
Hope it helps
Totally agree with #brian-agnew that if you have that many properties in 1 class then you probably need to do some refactoring as you almost certainly do not have enough separation of concerns.
However even after some refactoring, you will still have the properties, so it would be worth looking at the data validation attributes. For example, here is a walk though of using them with MVC: http://www.asp.net/mvc/tutorials/older-versions/models-(data)/validation-with-the-data-annotation-validators-cs. You could then use auto-implemented properties:
public int IntCard { get; set; }
Please note that this does not address your design issues. If your database is on sql-server, to avoid typing you could use a query like this (please modify for your requirement) to get the property list with datatypes and then copy and paste the results. SQL SERVER DEMO
SELECT 'public ' + CASE DATA_TYPE WHEN 'smallint' THEN 'short'
WHEN 'bit' THEN 'bool'
WHEN 'smalldatetime' THEN 'System.DateTime'
WHEN 'datetime' THEN 'System.DateTime'
WHEN 'date' THEN 'System.DateTime'
WHEN 'uniqueidentifier' THEN 'System.Guid'
WHEN 'varchar' THEN 'string'
WHEN 'int' THEN 'int'
WHEN 'numeric' THEN 'decimal'
ELSE DATA_TYPE END
+ CASE IS_NULLABLE WHEN 'NO' THEN '' ELSE '?' END
+ ' ' + COLUMN_NAME
+ ' { get; set; }' AS def
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'YourTableName'
ORDER BY IS_NULLABLE, ORDINAL_POSITION
Tim,
Based on your edit, you look like you are on the right lines. You should be breaking the properties down into specific items, for example:
public class Person
{
public string GivenName { get; set; }
public string Surname { get; set; }
public ContactInfo ContactInformation { get; set; }
}
public class Applicant : Person
{
public Person Spouse { get; set; }
public List<Person> Children { get; set; }
public List<Reference> References { get; set; }
}
public class ContactInfo
{
[Required]
[DataType(DataType.PhoneNumber)]
public string PhoneNumber { get; set; }
[DataType(DataType.EmailAddress)]
public string EmailAddress { get; set; }
public Address PrimaryAddress { get; set; }
public Address AlternativeAddress { get; set; }
}
So the key points for you here are that
the class are broken down into manageable, reusable chunks
Data Annotations (Required & DataType in the ContactInfo class) are used to validate properties
The properties no longer need explicit private variables
P.S. A bit more info about data annotations: http://msdn.microsoft.com/en-us/library/dd901590(v=vs.95).aspx

Categories

Resources