Linq - How to to create a list of categories which are included in another table - asp.net-mvc-4

I am trying to select from a list of categories where it matches the category type of a list of items using linq. IE, from a list of all the FIGstationeryCategories, select only the ones where the FiGStationeryType has a matching category from an already filtered list. The models are listed below.
public class FIGstationeryType
{
public int Id { get; set; }
public virtual FIGstationeryCategory Category { get; set; }
public virtual FIGcompany Company { get; set; }
public decimal Height { get; set; }
public decimal Width { get; set; }
public virtual FIGstationeryType Template { get; set; }
public bool DoubleSided { get; set; }
}
public class FIGstationeryCategory
{
public int Id { get; set; }
public string Name { get; set; }
public decimal MaxZoom { get; set; }
public ICollection<FIGstationeryType> StationeryItems { get; set; }
}
I have been going around in circles with this, and any help will be much appreciated. I haven't got very far! The first line of code works fine, it is the second one I am struggling with.
var listOfItems = db.StationeryTypes
.Where(C => C.Company.Users.Any(u => u.UserId == WebSecurity.CurrentUserId))
.ToList();
var categoryList = db.StationeryCategories
.Where(listOfItems
Any help would be much appreciated.

var listOfCategories =
(from o in listOfItems select o.Category.Name).Distinct().ToList();
When I thought about it (After watching 3 hours of linq videos last night), I realised that the listOfItems already held all the categories which where in use, so I didn't need to query and compare the two tables, just draw the relevant values from the list I already had.

I am not entirely sure how you want to select your categories but this probably goes a little way:
var categoryList = db.StationeryCategories
.*Select*(x => listOfItems.Where(y => y.Category == x)
.FirstOrDefault());
Can you clarify if this is the criteria you are after?

Related

.net Core Many to Many relationship

I am trying to determine what would be the smartest way to accomplish this. I may be way way overthinking what I am trying to do, but here goes.
I have the following entities, simplified
public class Meet
{
public int Id { get; set; }
//various properties
public List<MeetComp> Competitors { get; set; }
}
public class Competitor
{
public int Id { get; set; }
// various properties
public List<MeetComp> Meets { get; set; }
[ForeignKey("GymManager")]
public int GymManagerId { get; set; }
public GymManager GymManager { get; set; }
}
public class GymManager
{
public int Id { get; set; }
//various properties
public List<Competitor> Competitors { get; set; }
}
public class MeetComp
{
public int Id { get; set; }
[ForeignKey("Competitor")]
public int CompetitorId { get; set; }
public Competitor Competitor { get; set; }
[ForeignKey("Meet")]
public int MeetId { get; set; }
public Meet Meet { get; set; }
}
So I am creating a razor page where I get a specific Gymmanager and load all the related competitors to display in a list, which I have working just fine.
However I need another list (on the same page) of the related competitors of the Gymmanager but also who have an entry in the "MeetComp" table by a specific meetid. So List #1 is all of my Competitors and List #2 is all of my Comptetitors that are registered for that Meet.
Would it be smarter to have EF pull the data I get the data the first time with a ThenInclude()? Then I write some logic to determine if they get added to list #2? or should I make another trip to the Database? Then if I do make another trip to the database is there an easy to way to query for the List of CompId's I already have?
So here's what I ended up doing is making another trip to the DB.
public async Task<IActionResult> GetRegisteredComps(List<int> Comps, int meetid)
{
if(Comps.Count == 0)
{
return Ok();
}
if(meetid == 0)
{
return BadRequest();
}
var query = _context.MeetsComps.Include(c => c.Competitor)
.AsQueryable();
query = query.Where(c => c.MeetId == meetid);
query = query.Where(c => Comps.Contains(c.CompetitorId));
var results = await query.ToListAsync();
return Ok(results);
}

Is there a method to choose only some specific fields of a table using Automapper or EntityFramework?

I have a table in SqlServerDatabase. Table name is User(Id,Name,Paswd) and Im using automapper in Mvc4. Now i want only specific fields or 2 fields from the table instead of whole table, using automapper.how to do??
basically if the 2 objects have the same fields as in the little example
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Paswd { get; set; }
}
public class UserDto
{
public int Id { get; set; }
public string Name { get; set; }
public string Paswd { get; set; }
}
You just have to ignore the field
Mapper.CreateMap<User, UserDto>()
.ForMember(o => o.Paswd, m => m.Ignore());
You can find a lot of usefull example and features here
Automapepr Wiki

ASP.NET MVC: Need help organizing data structure classes

I come from a PHP/MySQL background, so maybe the problems I'm having with .NET stem from that. After a week of posting how to create an inventory tracker for our computer hardware and software, someone finally told me that he thought I was doing things wrong. The issue was not my code, but my design. That's certainly possible. I'm trying to do this in EF Code First and the idea of generating a database with code is foreign to me. However, I got the database working and everything was pointing to the right thing. But I can't pull what I need from the database.
What I want to do is create a dashboard page that would have categories for the types of hardware. So there would be a list of PCs, a list of monitors, a list of printers, etc. Initially, what I did was based on my knowledge of MySQL. I created a Hardware table (class) and a HardwareTypes table (class). In MySQL, what I would have done is put the ID for the HardwareType in the Hardware table, so I could do joins. Then I can get all of my PCs with a simple inner join.
.NET seems like it's different. It wants to create an intermediate table -- HardwareHardwareTypes, and then connect the two other tables. That seems strange, but OK. But when I go to get all of my PCs, I can't seem to get the help I need to write the query. So please take a look at my query and my classes, and let me know your thoughts.
Query, which returns Hardware, not HardwareTypes -- how do I get HardwareTypes?):
var pcs = db.Hardware.Where(h => h.HardwareType.Any(hwt => hwt.HType == "PC"));
ViewBag.Pcs = pcs.ToList();
Hardware class:
public class Hardware
{
public int Id { get; set; }
public virtual ICollection<DeviceType> Type { get; set; }
public string AssetTagId { get; set; }
public virtual ICollection<Manufacturer> Manufacturer { get; set; }
[Required]
[StringLength(50)]
public string ServiceTagId { get; set; }
[Required]
[StringLength(50)]
public string SerialNumber { get; set; }
[Required]
[StringLength(75)]
public string ProductNumber { get; set; }
// [Required]
[StringLength(20)]
public string PurchaseDate { get; set; }
[StringLength(20)]
public string WarrantyExpiration { get; set; }
[Required]
[StringLength(20)]
public string WarrantyType { get; set; }
public virtual ICollection<Location> Location { get; set; }
public virtual ICollection<HardwareType> HardwareType { get; set; }
[Required]
[StringLength(2000)]
public string Notes { get; set; }
public string POATag { get; set; }
}
HardwareTypes class:
public class HardwareType
{
public int Id { get; set; }
[Required]
[StringLength(128)]
public string HType { get; set; }
public virtual ICollection<Hardware> Hardware { get; set; }
}
Again, if what I need is more of a high-level design change, please let me know. If I need a different query, let me know that. The third (intermediate) table is dynamically generated and it's hard to know how to post that. I'd appreciate any and all help with this. What I need in the end is a list of PCs. Here is some sample seed data:
... new Hardware { AssetTagId = "2134",
Type = device.Where(h => h.DType == "Network Device").ToArray(),
Manufacturer = manuf.Where(h => h.ManufacturerName == "SonicWall").ToArray(),
ServiceTagId = "5243",
SerialNumber = "3456",
ProductNumber = "2345",
PurchaseDate = "2012-10-23",
WarrantyExpiration = "2012-11-12",
WarrantyType = "NBD",
Location = loc.Where(h => h.LocationName == "Paradise Lane").ToArray(),
Notes = "Scrapped",
HardwareType = htype.Where(h => h.HType == "PC").ToArray()}, ...
var htype = new List<HardwareType> {
new HardwareType { HType = "PC" },
new HardwareType { HType = "Monitor" },
new HardwareType { HType = "Printer" },
new HardwareType { HType = "Miscellaneous" }
};
If my seed data is structured wrong, please let me know that. Thanks.
Let me tell you first of all that the same database design which works in PHP/MySQL can work here also.
The easiest approach I will suggest to you is to create a view in the database which joins table Hardware and HardwareType, add nwly created view to you database model and fetch the desired data from the view instead of tables.

RavenDB TransformResults

I'm trying to use the TransformResults feature, and I can't get it to work. I'm not totally sure I understand this feature, perhaps there is another way to solve this problem. What I want is just the Id from the Order and the email addesses from the Customer and the Entrepreneur. I am happy for all tips that can take me in the right direction. Here is my code.
Document
public class OrderDocument
public string Id {get; set }
public EntrepreneurInfo EntrepreneurInfo { get; set; }
public CustomerInfo CustomerInfo { get; set; }
public OrderStatus CurrentOrderStatus { get; set; }
}
Info classes
public class EntrepreneurInfo
{
public string EntrepreneurDocumentId { get; set; }
public string Number { get; set; }
public string Name { get; set; }
}
public class CustomerInfo
{
public string CustomerDocumentId { get; set; }
public string Number { get; set; }
public string Name { get; set; }
}
The info classes are just subsets of a Customer and Entrepreneur documents respectively.
The Customer and Entrepreneur documents inherits from a base class ( AbstractOrganizationDocument) that has the EmailAddress property.
My Index
public class OrdersApprovedBroadcastingData :
AbstractIndexCreationTask<OrderDocument, OrdersApprovedBroadcastingData.ReduceResult>
{
public OrdersApprovedBroadcastingData()
{
this.Map = docs => from d in docs
where d.CurrentOrderStatus == OrderStatus.Approved
select new
{
Id = d.Id,
CustomerId = d.CustomerInfo.CustomerDocumentId,
EntrepreneurId = d.EntrepreneurInfo.EntrepreneurDocumentId
};
this.TransformResults = (db, orders) => from o in orders
let customer = db.Load<CustomerDocument>(o.CustomerId)
let entrepreneur = db.Load<EntrepreneurDocument>(o.EntrepreneurId)
select
new
{
o.Id,
o.CustomerId,
CustomerEmail = customer.EmailAddress,
o.EntrepreneurId,
EntrepreneurEmail = entrepreneur.EmailAddress
};
}
public class ReduceResult
{
public string Id { get; set; }
public string CustomerId { get; set; }
public string CustomerEmail { get; set; }
public string EntrepreneurId { get; set; }
public string EntrepreneurEmail { get; set; }
}
}
If I look at the result of this Index in Raven Studio I get null values for all fields except the Id. And finally here is my query.
Query
var items =
this.documentSession.Query<OrdersApprovedBroadcastingData.ReduceResult, OrdersApprovedBroadcastingData>()
.Select(x => new OrdersToBroadcastListItem
{
Id = x.Id,
CustomerEmailAddress = x.CustomerEmail,
EntrepreneurEmailAddress = x.EntrepreneurEmail
}).ToList();
Change your index to:
public class OrdersApprovedBroadcastingData : AbstractIndexCreationTask<OrderDocument>
{
public OrdersApprovedBroadcastingData()
{
Map = docs => from d in docs
where d.CurrentOrderStatus == OrderStatus.Approved
select new
{
};
TransformResults = (db, orders) =>
from o in orders
let customer = db.Load<CustomerDocument>(o.CustomerInfo.CustomerDocumentId)
let entrepreneur = db.Load<EntrepreneurDocument>(o.EntrepreneurInfo.EntrepreneurDocumentId)
select new
{
o.Id,
CustomerEmailAddress = customer.EmailAddress,
EntrepreneurEmailAddress = entrepreneur.EmailAddress
};
}
}
Your result class can simply be the final form of the projection, you don't need the intermediate step:
public class Result
{
public string Id { get; set; }
public string CustomerEmailAddress { get; set; }
public string EntrepreneurEmailAddress { get; set; }
}
You don't have to nest this class in the index if you don't want to. It doesn't matter either way. You can query either with:
var items = session.Query<Result, OrdersApprovedBroadcastingData>();
Or with
var items = session.Query<OrderDocument, OrdersApprovedBroadcastingData>().As<Result>();
Though, with the first way, the convention tends to be to nest the result class, so really it would be
var items = session.Query<OrderDocument.Result, OrdersApprovedBroadcastingData>();
Note in the index map, I am not including any properties at all. None are required for what you asked. However, if you want to add a Where or OrderBy clause to your query, any fields you might want to filter or sort on should be put in there.
One last thing - the convention you're using of OrderDocument, CustomerDocument, EntrepreneurDocument, is a bit strange. The usual convention is just Order, Customer, Entrepreneur. Think of your documents as the persisted form of the entities themselves. The convention you are using will work, it's just not the one usually used.

Using TransformResults to select hierarical data from RavenDB?

I have a simple class hierarchy looking like this:
public class Top
{
public string Id { get; set; }
public string Description { get; set; }
public List<Middle> Middles { get; set; }
}
public class Middle
{
public string Id { get; set; }
public string Description { get; set; }
public List<Bottom> Bottoms { get; set; }
}
public class Bottom
{
public string Id { get; set; }
public string Description { get; set; }
}
The whole thing is saved as entity of type 'Top'. Document is designed to preserve and reflect relationships/hierarchy but half but at time I will, for example, care only about an 'Id' and 'Description' of a given relationship. So, the types of queries I'd want to run are
select all Top,
select all Middle,
select Middle where Top.Id=somevalue
select Bottom where Top.Id=somevalue and Middle.Id=somevalue
I would like the results to be transformed and returned to me like this:
public class Result
{
public int Id { get; set; }
public string Description { get; set; }
}
How can I implement TransformResults (I presume that that's the feature that can be used) to achieve this? I've read quite a few examples but all of the sudden I see parameters/values, which were not declared anywhere and as a result I don't understand what's happening.
TransformResults doesn't have access to the outside world, you can't execute logic based on the query that you run.
You can flatten this structure, sure, but unless you will create multiple indexes with different TransformResults, you can't do this.
Note that this is a strange thing to do in the first place, because it doesn't matches the standard modeling of documents as a transaction boundary.