I have a 'GetTransactions' method that returns an object of type:
IList<ApplicationTransaction>
Where this is an ApplicationTransaction:
public partial class ApplicationTransaction
{
public int TransactionId { get; set; }
public int ApplicationId { get; set; }
public string Event { get; set; }
public System.DateTime CreatedOn { get; set; }
public virtual Application Application { get; set; }
}
How do I convert this LINQ query:
return (from t in GetTransactions().OfType<ApplicationTransaction>()
where t.Event == transactionType.ToString()
select t).FirstOrDefault();
Into fluent syntax?
This doesn't work - what am I not understanding?
return GetTransactions().OfType<ApplicationTransaction>().Where(t.Event == transactionType.ToString().FirstOrDefault();
You need parameter to a lambda in your where statement:
return GetTransactions()
.OfType<ApplicationTransaction>()
.Where(t => t.Event == transactionType.ToString())
.FirstOrDefault();
(Notice t => part where defines a new expression scope instead of directly trying to access a variable "t")
You don't need a separate select if you're selecting the whole entity.
I also suggest using the multiline layout I used in the answer to understand the query better and catch potential problems like the missing parenthesis issue #nvoigt mentioned.
Related
I have two different classes:
The following is a model for the database table named "Attachments":
namespace WebApi.Models
{
public class Attachment
{
public enum EntityType
{
Transaction
}
public int AttachmentId { get; set; }
public int EntityId { get; set; }
public EntityType Type { get; set; }
public string Filename { get; set; }
public DateTime Created { get; set; }
public DateTime Updated { get; set; }
}
}
and in my dbContext class I have something like the following:
namespace WebApi.Models
{
public class accountingContext : DbContext
{
public DbSet<User>? Users { get; set; }
public DbSet<Transaction>? Transactions { get; set; }
public DbSet<Attachment>? Attachments { get; set; }
///...
}
}
and then I have a similar cvlass to the Attachement model which is usedf to send data back in response to a web api request, the class is below:
namespace WebApi.Entities.AttachmentResponse;
public class AttachmentResponse
{
public int AttachmentId { get; set }
public string Filename { get; set; }
}
I wish to keep my class for responses seperate rather then using the model classes for reasons I don't feel worthwhile going into.
After performing a query against the model classes I need to convert the result and map to the AttachmentResponse class. I am trying the following:
List<WebApi.Entities.AttachmentResponse> attachments = (
from a in db.Attachments
from t in db.Transactions.Where(t => a.EntityId == t.TransactionId && t.UserId == userId)
where a.EntityId == EntityId
select new
{
a.AttachmentId,
a.Filename
}).ToList();
But I get an error with the above attempt. I have also looked at ConvertAll but cannot see how to use it in the code above.
Is it possible to accomplish what I am attempting? If so, where am I going wrong above?
You're creating a list of an anonymous type, not a list of AttachmentResponse objects. You need to explicitly create them in the projection:
select new AttachmentResponse
{
AttachmentId = a.AttachmentId,
Filename = a.Filename
}
I would also look at tools like AutoMapper that can create mappings very easily, especially when the property names are the same.
I can't comment, so I can't ask what error you're getting. However, from looking at it, it looks like a casting problem. You can cast anonymous types to other types. Using just new makes is anonymous instead specify they type that you are declaring new.
List<WebApi.Entities.AttachmentResponse> attachments = (
from a in db.Attachments
from t in db.Transactions.Where(t => a.EntityId == t.TransactionId && t.UserId == userId)
where a.EntityId == EntityId
select new WebApi.Entities.AttachmentResponse
{
a.AttachmentId,
a.Filename
}).ToList();
I am trying to perform a search over an index for the following object:
public class IndexedElement
{
public Guid Id { get; set; }
public long RowId { get; set; }
public IndexedElementType Type { get; set; }
public string Summary { get; set; }
public string Description { get; set; }
public IList<string> Tags { get; set; }
}
The purpose is to search by the Summary property, or by matching any of the strings inside the Tags collections
What I currently have is this:
public IEnumerable<IndexedElement> Search(string description)
{
var query = GetClient().Search<IndexedElement>(s => s.From(0).Size(5)
.Query(
q => q.Term(p => p.Summary, description)
||
q.Nested(n => n.Path(p => p.Tags).Query(q2 => q2.Terms(t => t.Field(f => f.Tags).Terms(description))))
));
return query.Documents.ToList();
}
But the Nested part is not working, I don't know if I am using it in the proper way or maybe I have to find another solution for that.
Any ideas?
Thank you all in advance
You don't need to perform a nested query to query the Tags field, as each tag is only a primitive JSON value i.e. a string. Just the terms query will suffice.
Where a nested query would be needed is where Tags is a POCO with multiple properties and is mapped as a nested datatype.
I have two models:
public class HouseType
{
public int Id { get; set; }
public string TypeName { get; set; }
public virtual IEnumerable<HouseModel> HouseModels { get; set; }
}
and
public class HouseModel
{
public int Id { get; set; }
public string ModelName { get; set; }
[DisplayFormat(DataFormatString = "{0:n2}")]
public double StandardPrice { get; set; }
[ForeignKey("HouseType")]
public int HouseTypeID { get; set; }
public virtual HouseType HouseType { get; set; }
public virtual IEnumerable<HouseUnit> HouseUnits { get; set; }
}
I am returning a JSON result, so as expected I cannot manipulate it in a view, because the display is handled by a javascript file that I made.
I am trying to retrieve the number of HouseModel that is contained by HouseType. I have tried:
db.HouseTypes.Select(h => new
{
HouseCount = h.HouseModels.Count()
}).ToList();
But Entity Framework complains about it. How can I access the count of related records inside an entity? Any help will be much appreciated. Thanks.
Use
public virtual ICollection<HouseUnit> HouseUnits { get; set; }
instead of
public virtual IEnumerable<HouseUnit> HouseUnits { get; set; }
Hope this helps.
Simply speaking, the trouble is that EF is trying to execute the .Select() statement on the db server but, of course, the db server does not know how to create a new object.
You first need to bring back the counts then create your objects so something like this should work better:
var listOfCounts = db.HouseTypes
.Select(h => h.HouseModels.Count())
.ToList()
.Select(c => new
{
HouseCount = c
})
.ToList();
in this example when the first .ToList() is executed the db needs only return a set of numbers (the counts of HouseModels in each HouseType) then we have a List<int> in local memory from which we can create our objects with the second Select statement.
As an aside...
It wasn't part of your original question but maybe you'd want to consider a dictionary rather than a list so you have some means of identifying which count of HouseModels belonged to each HouseType? in which case we could do something like:
Dictionary<int,string> houseModelCounts = db.HouseTypes
.ToDictionary(h => h.Id, h => h.HouseModels.Count());
which would give a dictionary keyed with the HouseType Id with values for the count of HouseModels in each type. I don't know your context though so maybe unnecessary for you?
I have the following:
public partial class Subject
{
public Subject()
{
this.Contents = new List<Content>();
}
public int SubjectId { get; set; }
public string Name { get; set; }
public virtual ICollection<Content> Contents { get; set; }
}
public partial class Content
{
public int ContentId { get; set; }
public int ContentTypeId { get; set; }
public string Title { get; set; }
public string Text { get; set; }
public int SubjectId { get; set; }
public virtual Subject Subject { get; set; }
}
In my SQL Server database I have an index on the Content table of SubectId and ContentTypeId
My classes are working find with a standard repository that has such methods such as GetAll() and GetId(id) however using the repository model is there a way I can do more complex queries. In this case I would somehow want todo a query for a particular SujectId and a contentTypeId. What I want to avoid is having a query that gets every content record and then filters out what I need. I'd like some way to send a real query of exactly what I need to SQL Server.
Currently my generic repository has the following:
public virtual T GetById(int id)
{
return DbSet.Find(id);
}
Could I do what I need by implementing creating a ContentRepository and having something like the following:
public IQuerable<Content> GetAllBySubjectId(int id)
{
return DbSet.Where(c => c.SubjectId == id);
}
If so then how could I use the GetAllBySubjectId and add in the check for where ContentId == "01" for example?
You could add to your repository a method like this:
public IQueryable<T> Find(Expression<Func<T, bool>> predicate)
{
return DbSet.Where<T>(predicate);
}
Then write sth like:
repository.Find(c => c.SubjectId == myId);
If you use Entity Framework with LINQ, it will try to generate and send optimized queries to the database, for example, if you do something like:
var contents =
from c in Context.Contents // or directly the DbSet of Contents
where c.ContentTypeId == 2
select new { c.Title, c.ContentId };
It should generate a query along the lines of the following (you can use a SQL Profiler):
select
c.Title as Title,
c.ContentId as ContentId
from Contents c
where
c.ContentTypeId == 2
There are some considerations to think of, but most of the time EF will generate good performance queries.
To know more about that, I recommend the following URL: http://www.sql-server-performance.com/2012/entity-framework-performance-optimization/
I'm trying to order my results by the value in an embedded document.
Consider a model such as:
public class Car
{
public Guid ID { get; set; }
public string Name { get; set; }
public IEnumerable<Passenger> Passengers { get; set; }
}
public class Passenger
{
public Guid ID { get; set; }
public virtual string Name { get; set; }
public virtual int Age { get; set; }
}
I'm trying to query my Car collection, and order by Passenger.Age
My query looks something like:
var results = (from car in _db.GetCollection<Car>("car").AsEnumerable()
from passenger in car.Passengers
where car.Name == "Ford"
orderby passenger.Age).ToList();
With this, I get the following exception:
The SelectMany query operator is not supported.
This is understandably a limitation of the C# mongo driver.
Is there a workaround?
Failing that, how could I order them after my .ToList() ?
You can probably re-write this with AsQueryable() to get an IEnumerable collection from ToList() back, from which you can then further query with any LINQ you want to use, not just the operations directly supported by the MongoCollection:
var passengers = _db.GetCollection<Car>("car").AsQueryable().ToList()
.Where(car => car.Name == "Ford")
.SelectMany(ford => ford.Passengers)
.OrderBy(p => p.Age);
Here's where you can find the directly supported LINQ operations for the MongoDb C# driver.