LINQ JOIN with WHERE condition - asp.net-mvc

I have a problem with the creation of LINQ query with lambda expression. I need join two tables and make some conditions. I have two tables MSR and BOMDetail.
MSR had theese columns -> MSRID, PN, Buyer,Plant EditDate.
BomDetail had theese columns -> BOMID, PN, AltQty, Plant, EditDate.
And i need to write this query into LINQ.
SELECT MSR.PN, Buyer, MSR.EditDate, MSR.Plant FROM MSR
JOIN BomDetail bd ON MSR.PN = bd.PN AND MSR.Plant = bd.Plant
WHERE LEN(ISNULL(bd.AltQty,''))>0
I need to make 2 conditions PN must equals between tables and Plant's too.
I have for result ViewModel in asp.net MVC.
public class MSRViewModel
{
public string PN { get; set; }
public string Buyer { get; set; }
public string Plant { get; set; }
public DateTime EditDate { get; set; }
}
And here is my sample, it works fine, but i don't know where i must write the second condition for bd.Plant = MSR.Plant.
var data = DbContext.BomDetails.Where(x => !string.IsNullOrEmpty(x.AltQty))
.Join(DbContext.MSRs
, bd => bd.PN,
msr => msr.PN,
(bd, msr) => new MSRViewModel
{
PN = msr.PN,
Buyer = msr.Buyer,
Plant = msr.Plant,
EditDate = msr.EditDate
}).ToList().AsEnumerable();
Thanks.

You can do this as follows:
var data = DbContext.BomDetails.Where(x => !string.IsNullOrEmpty(x.AltQty))
.Join(DbContext.MSRs
, bd => new { bd.PN, bd.Plant },
msr => new { msr.PN, msr.Plant },
(bd, msr) => new MSRViewModel
{
PN = msr.PN,
Buyer = msr.Buyer,
Plant = msr.Plant,
EditDate = msr.EditDate
}).ToList().AsEnumerable();

Related

How do I take last n elements from nested collection

I am buinding a chat for an application, so when a user logs in I need to send them all 'unseen' messages, I am using entityframework, Id like to return only the last 20 unseen messages. but my query is not working, currently I get this exception
Count must be a DbConstantExpression or a DbParameterReferenceExpression
what am I doing wrong?
List<ChatVM> unSeenChats = db.Chats.Where(chat => !chat.Seen)
.Select(chat => new ChatVM
{
Id = chat.Id,
IsAnnonymous = chat.IsAnnonymous,
UserName = chat.UserName,
Messages = chat.Messages
.OrderBy(x => x.DateTime)
.Skip(chat.Messages.Count - 20 > 0
? chat.Messages.Count - 20
: 0)
.Take(20)
.Select(message => new MessageVM
{
Id = message.Id,
DateTime = message.DateTime,
Text = message.Text
}).ToList()
}).ToList();
my models are as follows:
public class Chat
{
...
public virtual ICollection<Message> Messages { get; set; }
}
public class Message
{
...
public int ChatId { get; set; }
public virtual Chat Chat { get; set; }
}
public class Entities : IdentityDbContext<ApplicationUser>
{
....
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
...
modelBuilder.Entity<Message>()
.HasRequired(p => p.Chat).WithMany(p => p.Messages).WillCascadeOnDelete(true);
}
}
thanks
I don't think you're allowed to use .Count from within the query (hence the error that you're seeing). In any case, I think you're looking at this from the wrong perspective. You should probably be using the OrderByDescending method, and then just grab the first 20 posts from there.
Something like this:
List<ChatVM> unSeenChats = db.Chats.Where(chat => !chat.Seen)
.Select(chat => new ChatVM
{
Id = chat.Id,
IsAnnonymous = chat.IsAnnonymous,
UserName = chat.UserName,
Messages = chat.Messages
.OrderByDescending(x => x.DateTime)
.Take(20)
.Select(message => new MessageVM
{
Id = message.Id,
DateTime = message.DateTime,
Text = message.Text
}).ToList()
}).ToList();

Neo4jClient: How to deserialize a collect result to a c# class

I have a query where I want only Id and name of the collection back to reduce the network traffic. I am able to get what i want from the database with the following part of the query
ShipToCities = Return.As<IEnumerable<string>>("COLLECT( [shipTo.InternalId, shipTo.Name])")
but the issue is i get back the data like this:
[ [ "IN.KA.MANG", "Mangalore" ], [ "IN.KA.MANG", "Mangalore" ], [ "IN.KA.BANG", "Bangalore" ] ]
but how can I map it to a C# object like
public class CityFound
{
public string CityId { get; set; }
public string CityName { get; set; }
}
is there a way to use some converter to achieve this without me having to use some ugly string manipulation myself?
UPDATE 1:
Actually my query is fairly complex and only way to get the data that I can think of is to handcraft the query like below to reduce the :
//selectedLoadQuery below is a complex query based on user selection...
var query = selectedLoadQuery
.Match("(load)-[:SHIPPED_BY]->(shipper)-[r:HAS_TRANSPORTER]->(transporter)")
.With("load, transporter, shipper, user, count(DISTINCT r) as MyClients")
.Match("p=(shipFrom:City)<-[:SHIP_FROM_CITY]-(load)-[:SHIP_TO_CITY]->(shipTo:City)")
.With("p, load, shipFrom, shipTo, transporter, MyClients")
.Return((load, shipFrom, shipTo) => new
{
TotalShipments = load.CountDistinct(),
FromMyClients = Return.As<long>("MyClients"),
ShipFromCities = Return.As<IEnumerable<string>>("COLLECT( [shipFrom.InternalId, shipFrom.Name])"),
ShipToCities = Return.As<IEnumerable<string>>("COLLECT( [shipTo.InternalId, shipTo.Name])"),
});
Regards
Kiran
You don't need to get so creative. You're only getting into this issue because you're hand crafting such a complex query that flattens out the structure of the data.
Create a class that describes what's in the node:
public class ShippingDestination
{
public long InternalId { get; set; }
public string Name { get; set; }
}
Use this to light up the following syntax in your Return statement:
var cities = graphClient
.Match(...)
.Return(shipTo => new {
Id = shipTo.As<ShippingDestination>().InternalId,
Name = shipTo.As<ShippingDestination>().Name,
})
.Results;

Custom grid using Telerik pluggin in nopcommerce 2.8

Iam working on nopcommerce2.8 version. I have a problem with telerik plugin implementation to create new grid.
Iam implementing a concept where for a product i want to give different price for different customer. So to assign new price for different customers, in admin panel i am creating a grid in edit productvariant page using telerik. I have created a new tab to display these details. Iam able to display customer name and price in grid, but i am not able to call update function, when i click on update button after editing a row. The same update function i called for Deleting the grid row also, so when i click on delete the same update function getting trigger. I think some setting has been missed in View. Please help me to solve this update issue.
The model, view and controller of my nopcommerce in given below.
Thanks.
//Model
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
using FluentValidation.Attributes;
using Nop.Admin.Models.Customers;
using Nop.Admin.Validators.Catalog;
using Nop.Web.Framework;
using Nop.Web.Framework.Localization;
using Nop.Web.Framework.Mvc;
using Telerik.Web.Mvc;
namespace Nop.Admin.Models.Catalog
{
public partial class CustomerProductPriceModel : BaseNopModel
{
public int Customer_Id { get; set; }
[NopResourceDisplayName("Customer Name")]
public string Customer_name { get; set; }
[NopResourceDisplayName("Price")]
public decimal Price { get; set; }
[NopResourceDisplayName("Unit")]
public string Units { get; set; }
}
}
// view
#(Html.Telerik().Grid<CustomerProductPriceModel>()
.Name("Grid")
.DataKeys(x =>
{
x.Add(y => y.Customer_Id);
})
.DataBinding(dataBinding =>
{
dataBinding.Ajax()
.Select("CustomerProductPriceList", "ProductVariant", new { productVariantId = Model.Id })
.Update("CustomerPriceUpdate", "ProductVariant", new { productVariantId = Model.Id })
.Delete("CustomerPriceUpdate", "ProductVariant", new { productVariantId = Model.Id });
})
.Columns(columns =>
{
columns.Bound(y => y.Customer_name).Width(200).ReadOnly();
columns.Bound(y => y.Price).Width(100);
columns.Command(commands =>
{
commands.Edit().Text(T("Admin.Common.Edit").Text);
commands.Delete().Text(T("Admin.Common.Delete").Text);
}).Width(180);
})
.Editable(x =>
{
x.Mode(GridEditMode.InLine);
})
.EnableCustomBinding(true)
)
// controller
[GridAction(EnableCustomBinding = true)]
public ActionResult CustomerPriceUpdate(GridCommand command, CustomerProductPriceModel model, int productVariantId)
{
if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog))
return AccessDeniedView();
return CustomerProductPriceList(command, productVariantId);
}
[HttpPost, GridAction(EnableCustomBinding = true)]
public ActionResult CustomerProductPriceList(GridCommand command, int productVariantId)
{
if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog))
return AccessDeniedView();
var productVariant = _productService.GetProductVariantById(productVariantId);
if (productVariant == null)
throw new ArgumentException("No product variant found with the specified id");
var CustomerPrices = PrepareCustomerProductPriceModel(productVariant.Product.Id);
var CustomerPricesa = CustomerPrices
.Select(x =>
{
return new CustomerProductPriceModel()
{
Customer_Id = x.Customer_Id,
Price = x.Price,
Units = x.Units,
Customer_name = x.Customer_name
};
})
.ToList();
var model = new GridModel<CustomerProductPriceModel>
{
Data = CustomerPricesa,
Total = CustomerPrices.Count
};
return new JsonResult
{
Data = model
};
}
Is there a reason not to use the built-in customer price levels already in place in nopCommerce, or are you wanting to display all prices at once?

selecting multiple columns and looping through the selected rows

I want to be able to select multiple columns and loop through the retrieved rows and store the selected fields in a string.
Something like select a.firstname, a.lastname from customer where a.id = '123' and loop through the retireved rows and have them write to a string like
FirstName = John; LastName = Doe
FirstName = Steve; LastName = Smith
I have linq statement as
IList<string> strgradeandbatch = new List<string>();
strgradeandbatch = context.GradeAndBatches
.Where(T => T.RequestGuid == request.ItemGuid)
.Select(T => new{T.GradeName, T.Batch}).ToList();
Obviously this is wrong, and not sure how to do it.Thanks for your help in advance
I think you are almost correct. Just remove IList<string> strgradeandbatch = new List<string>() and use anonymous type var strgradeandbatch.
string GradeName, Batch;
var strgradeandbatch = context.GradeAndBatches
.Where(T => T.RequestGuid == request.ItemGuid)
.Select(T => new{T.GradeName, T.Batch}).ToList();
foreach(var item in strgradeandbatch)
{
GradeName = item.GradeName;
Batch = item.Batch;
}
(Note:If you use anonymous type, you can't return this value from the method)
The Select method projects the query results into a list of an anonymous type objects, so it can be used with a list for strings.
One solution is to create a new class
public class Grade
{
public string GradeName {get; set;}
public string Batch {get; set;}
}
Which is going to be used with the Select method
var strgradeandbatch = context.GradeAndBatches
.Where(T => T.RequestGuid == request.ItemGuid)
.Select(T => new Grade
{
GradeName = T.GradeName,
Batch = T.Batch
}).ToList();

Mixing local list operations with linq to entities database operations

I have 2 lists. A shopping cart list, which contains a objects with the properties; Quantity and ProductId. I then get all products from the repository (IQueryable) that has ProductId in the shopping cart list. This means that for every product, there is a shopping cart object with the Quantity related to it.
When doing the select, I want to assign this Quantity also, but the only way I know to do this is to query the cart again.
For egx.
model = (from p in productService.GetAllProducts()
where cart.Entries.Select(c => c.ProductId).Contains(p.ProductId)
select new CartViewItem
{
Price = p.Price,
ProductId = p.ProductId,
ProductName = p.ProductName,
Quantity = cart.Entries.FirstOrDefault(c => c.ProductId == p.ProductId).Quantity
}).ToList();
Model:
public class ShoppingCartEntry
{
public int ProductId { get; set; }
public int Quantity { get; set; }
}
cart.Entries is not coming from a repository. productService.GetAllProducts() returns an entityframework's IQueryable.
EDIT: My new code is:
model= (from p in productService.GetAllProducts()
from c in cart.Entries
where c.ProductId == p.ProductId
select new CartViewItem
{
Price = p.Price,
ProductId = p.ProductId,
ProductName = p.ProductName,
Quantity = c.Quantity
}).ToList();
This throws an error:
Unable to create a constant value of type 'SampleApp.WebUI.Models.ShoppingCartEntry'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
i think this should work...
var model = (from c in cart.Entires // The small local cart collection
let cpid = cart.Entires.Select(c2 => c2.ProjectId) //
from p in productService.GetAllProducts() // Query all Products used in cart
.Where(queryp => cpid.Contains(queryp.ProjectId)).ToList()
where p.ProductId == c.ProductId
select new CartViewItem {
p.Price,
p.ProductId,
p.Brand,
p.ProductName,
Discount = p.DiscountPercent * c.Quantity}).ToList();

Resources