I'm writing code using eager loading to load the related data from Assigned using the Include method. I'm trying to get the value for IsAvailable, as to access the data from Assigned and check if there is a record which have the value of ReturnDate is equal to null. I keep on getting an error saying
ICollection does not contain a definition for Any
public ActionResult Index()
{
var item = db.Item.Include(h => h.Assigned).Select(b => new ItemViewModel
{
ItemID = b.ItemID,
ItemName = b.ItemName,
Category = b.Category,
Description = b.Description,
Model = b.Model,
IsAvailable = !b.Assigned.Any(h => h.ReturnDate == null)
}).ToList();
return View(item);
}
ItemViewModel
public class ItemViewModel
{
public int ItemID { get; set;}
[Display(Name = "Item")]
public string ItemName { get; set; }
[Required(ErrorMessage = "Category is required")]
public string Category { get; set; }
public string Model { get; set; }
public string Description { get; set; }
public bool IsAvailable { get; set; }
}
Item class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.Collections;
namespace Inventoryproto3.Models
{
public class Item
{
public int ItemID { get; set; }
[Required(ErrorMessage ="Please enter a title"),Display(Name ="Item")]
public string ItemName { get; set;}
[Required(ErrorMessage ="Category is required")]
public string Category { get; set;}
public string Model { get; set;}
public string Description{get; set;}
public ICollection Assigned { get; set; }
}
}
'System.Collections.Generic.ICollection' does not contain a definition for 'Any' and no accessible extension method 'Any' accepting a first argument of type 'System.Collections.Generic.ICollection' could be found (are you missing a using directive or an assembly reference?
Screenshot of error
Every Item has a property Assigned, which is of type ICollection.
If you look at the definition of Queryable.Any you'll find:
public static bool Any<TSource> (this IQueryable<TSource> source,
Expression<Func<TSource,bool>> predicate);
Therefore property Assigned should implement ICollection<TSource> where TSource is the actual type you expect to find in your collection.
The proper solution would be to change the type of property Assigned, such that you know that the collection only contains items of the type you expect. Alas you chose to give us a lot of unimportant information, but you forgot to mention the class of items in Assigned, so let's assume it's of type MyClass.
class MyClass
{
public Datetime ReturnDate {get; set;}
...
}
class Item
{
...
public ICollection<MyClass> Assigned {get; set;}
}
This will solve your problem: Any(...) works, and you are certain that people can only put MyClass objects in the collection.
If you don't want to limit your collection to MyClass objects, you can at least limit yourself to classes with property ReturnDate:
interface IMyInterface
{
public Datetime ReturnDate {get; set;}
}
class Item
{
...
public ICollection<IMyInterface> Assigned {get; set;}
}
If you really want that people can add other things than MyClass objects in the collection, something I strongly advise against, you'll have to specify what you want:
Ignore items in the collection that are not MyClass objects? Use OfType
Just hope that no one ever put something else in the collection? Use Cast, but then again: why not prevent that someone puts an incorrect object in the class, and define ICollection<MyClass>?
OfType probably does not works AsQueryable, in that case you should move the data to your local process using AsEnumerable. A third reason to use a correct type for ICollection right.
IsAvailable = !b.Assigned.OfType<MyClass>().Any(h => h.ReturnDate == null);
IsAvailable = !b.Assigned.Cast<MyClass>().Any(h => h.ReturnDate == null);
The first one will ignore items of your collection with other types. The latter one will throw an exception if there is another type in your collection (fourth reason to make it an ICollection<MyClass>
Related
I have the following models:
public class Item {
public string ItemID {get; set;}
public decimal AvailableQuantity {get; set;}
}
public class Element {
public string ElementID {get; set;}
[ForeignKey("Item")]
public string ItemID { get; set; }
public virtual Item Item { get; set; }
public decimal Quantity {get; set;}
}
I want the Quantity field from Element to be always less than the Item that it's representing. I tried using the Foolproof data annotation:
[Foolproof.LessThanOrEqualTo(Item.AvailableQuantity)]
public decimal Quantity { get; set; }
but I get the following error:
CS0120: An object reference is required for the non-static field, method, or property 'Element.Item'
What can I do to satisfy this condition? I want to use it for data validation in form.
I think you have another problem too:
public class Item {
public string ItemID {get; set;}
public decimal AvailableQuantity {get; set;}
}
public class Element {
public string ElementID {get; set;}
[ForeignKey("Item")] // you dont have a property called Item here except from the Item
object which cant be used as a foreign key.
public string ItemID { get; set; }
[ForeignKey("ItemID")] //this will work
public virtual Item Item { get; set; }
public decimal Quantity {get; set;}
}
As for data annotation Foolproof has options but i think you cant do it on these models.
Try it Creating a ViewModel so the properties comparing are in the same model;
This may work:
[GreaterThan("Quantity")]
Let's take an example model:
public class Person
{
public string Name {get; set;}
public List<Guitar> Guitars {get; set;}
}
public class Guitar
{
public string Brand {get; set;}
public string Model {get; set;}
}
I need to create a View with a list of all People and a count of how many guitars they have. To do that I would like to pass a ViewModel like this one populated with EF without loading all Guitards:
// This will be send to the View, I can also just send a List
public class ViewModelPassed
{
List<PeopleGuitarViewModel> AllPeople { get; set; }
}
// This should be populated from EF
public class PeopleGuitarViewModel
{
public string Name { get; set; }
public int NumberOfGuitars { get; set; }
}
Can I query EF to a different class, and avoid bringing the whole list of guitars and instead get a COUNT in SQL?
Thanks!
You should provide primary key to your models for EF core to create the relationship:
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
public List<Guitar> Guitars { get; set; }
}
public class Guitar
{
public int ID { get; set; }
public string Brand { get; set; }
public string Model { get; set; }
}
Also use public for AllPeople property in ViewModelPassed:
public List<PeopleGuitarViewModel> AllPeople { get; set; }
Then query like :
ViewModelPassed modelPassed = new ViewModelPassed();
modelPassed.AllPeople = new List<PeopleGuitarViewModel>();
modelPassed.AllPeople = _applicationDbContext.Persons.Select(x =>
new PeopleGuitarViewModel
{
Name = x.Name,
NumberOfGuitars = x.Guitars.Count
}).ToList();
One way is to do it like this:
var viewModel=context.Persons.Select(x=>new PeopleGuitarViewModel
{
Name=x.Name,
NumberOfGuitars=Guitars.Count()
}).ToList();
this kind of query is also named Projection and is consider best practice (do not send full entity to the view).
There are 2 libraries which I often use for such projections: AutoMapper and/or Mapster.
Hope this help you.
When populating your ViewModel, you can use Linq to get the count. Like this:
PeopleGuitarViewModel p= new PeopleGuitarViewModel();
p.Name = person.Name;
p.NumberOfGuitars = person.Guitars.Count;
Where person is an object of your Person class.
The problem: I am trying to create a general method that will take in an IQueryable which can be many different types of data including custom. In this method I will be doing a sort depending on the type of IQueryable that is being passed in.
What I am doing is creating a custom class with the following:
public class sortObject
{
public String OrderParam { get; set; }
public int pageSize { get; set; }
public int pageIndex { get; set; }//This is what page the user is on
public IQueryable<dynamic> entity { get; set; }
}
I will pass in an IQueryable object to this object like so:
sortObject so = new sortObject();
so.entity = _context.userAcount.Select(x=>x);
...
The so.entity will be IQueryable<dynamic> but in the base section of the object (while in debugging) will be of type userAccount. I want the data in the base in order to run the search.
My issue is that I do not know what the IQueryable type is until run time since this is a general method. It can be of type user, or of type address etc, but the sorting will still work because I will pass in what I want to order this by in the sortObject.
How can I either get the base data or convert the IQueryable type at runtime?
I found that this works in the sort table method:
var entity = so.entity.AsQueryable().OrderBy("UserName");
var data = entity.Skip(so.pageSize*(so.pageIndex-1)).Take(so.pageSize);
I think what you want is a solution involving generics - try
public class sortObject<T>
{
public String OrderParam { get; set; }
public int pageSize { get; set; }
public int pageIndex { get; set; }//This is what page the user is on
public IQueryable<T> entity { get; set; }
}
This will allow you to declare a sortObject with an entity of whatever type you want the IQuerable to contain.
You can make your method be something like
public void DoSomething<T>(sortObject<T> input)
{
// input.entity is now of type T
}
and you can call
sortObject so = new sortObject<userAccount>();
so.entity = _context.userAcount.Select(x=>x);
DoSomething(so);
My objective is to return two properties from two related nodes.
I want to return DataSpaceName from DataSpace and EntityName from Entity from the two nodes matched by the DataSpaceName/DataSpace property.
public class DataSpace
{
public string DataSpaceName { get; set;}
public string DataSpaceDescription { get; set;}
public string ConnectionString { get; set;}
}
public class Entity
{
public string DataConnector { get; set;}
public string EntityName { get; set;}
public string EntityType { get; set;}
public string DataSpace{get; set;}
}
var query =
client
.Cypher
.Match("(DataSpace:DataSpace), (Entity:Entity)")
.Where("Entity.DataSpace = DataSpace.DataSpaceName")
.Return ((DataSpace,Entity) => new {
DSName = Return.As<string>("DataSpace.DataSpaceName"),
EName=Return.As<string>("Entity.EntityName")
});
This throws an error :
Compiler Error Message: CS0103: The name 'Return' does not exist in the current context
Instead of Return, if I use the Node (say DataSpace.As() ) I get the entire DataSpace Node.
Can somebody throw light on the mistake Im making in this.
It looks like you've only imported the Neo4jClient namespace. You need to import Neo4jClient.Cypher as well if you want to use the Return class.
ReSharper would have also suggested this for you.
i'd like to know, I have a application in asp.net mvc and nhibernate. I've read about that in the Views on asp.net mvc, shouldn't know about the Domain, and it need use a DTO object. So, I'm trying to do this, I found the AutoMapper component and I don't know the correct way to do my DTOS, for some domain objects. I have a domain class like this:
public class Entity
{
public virtual int Id { get; set; }
public virtual bool Active { get; set; }
}
public class Category : Entity
{
public virtual string Name { get; set; }
public virtual IList<Product> Products { get; set; }
public Category() { }
}
public class Product : Entity
{
public virtual string Name { get; set; }
public virtual string Details { get; set; }
public virtual decimal Prince { get; set; }
public virtual int Stock { get; set; }
public virtual Category Category { get; set; }
public virtual Supplier Supplier { get; set; }
public Product() { }
}
public class Supplier : Entity
{
public virtual string Name { get; set; }
public virtual IList<Product> Products { get; set; }
public Supplier() { }
}
I'd like to get some example of how can I do my DTOs to View ? Need I use only strings in DTO ? And my controllers, it should get a domain object or a DTO and transform it on a domain to save in repository ?
Thanks a lot!
Cheers
There is no guidelines on this matter and it depends on your personal chice. I have few advices that have proven useful in practice:
1. Use flat DTOs - this means that the properties of the DTO must be as primitive as possible. This saves you the need for null reference checking.
For example if you have a domain object like this:
public class Employee
{
prop string FirstName{get; set;}
prop string LastName{get; set;}
prop Employee Boss{get; set;}
...
}
And you need to output in a grid a list of employees and display information for their 1st level boss I prefer to create a DTO
public class EmployeeDTO
{
prop string FirstName{get; set;}
prop string LastName{get; set;}
prop bool HaveABoss{get;set}
prop string BossFirstName{get; set;}
prop string BossLastName{get; set;}
...
}
or something like this (-:
2. Do not convert everything to sting - this will bind the DTO to a concrete view because you'll apply special formatting. It's not a problem to apply simple formatting directly in the view.
3. Use DTOs in your post actions and than convert them to domain objects. Usually controller's actions are the first line of deffence against incorrect data and you cannot expect to be able to allways construct a valid domain object out of the user's input. In most cases you have to do some post-processing like validation, setting default values and so on. After that you can create your DTOs.