Я делаю этот метод для глубокого присваивания с помощью es6.
function isObject(item) {
return (item && typeof item === 'object' && !Array.isArray(item) && item !== null)
}
function deepAssign(...objs) {
if (objs.length < 2) {
throw new Error('Need two or more objects to merge')
}
const target = objs[0]
for (let i = 1; i < objs.length; i++) {
const source = objs[i]
Object.keys(source).forEach(prop => {
const value = source[prop]
if (isObject(value)) {
if (target.hasOwnProperty(prop) && isObject(target[prop])) {
target[prop] = deepAssign(target[prop], value)
} else {
target[prop] = value
}
} else if (Array.isArray(value)) {
if (target.hasOwnProperty(prop) && Array.isArray(target[prop])) {
const targetArray = target[prop]
value.forEach((sourceItem, itemIndex) => {
if (itemIndex < targetArray.length) {
const targetItem = targetArray[itemIndex]
if (Object.is(targetItem, sourceItem)) {
return
}
if (isObject(targetItem) && isObject(sourceItem)) {
targetArray[itemIndex] = deepAssign(targetItem, sourceItem)
} else if (Array.isArray(targetItem) && Array.isArray(sourceItem)) {
targetArray[itemIndex] = deepAssign(targetItem, sourceItem)
} else {
targetArray[itemIndex] = sourceItem
}
} else {
targetArray.push(sourceItem)
}
})
} else {
target[prop] = value
}
} else {
target[prop] = value
}
})
}
return target
}
Вы не можете (и не должны) проектировать на сопоставленную сущность. Вы можете, однако, проецировать на анонимный тип или на DTO :
public class ProductDTO
{
public string Name { get; set; }
// Other field you may need from the Product entity
}
И ваш метод вернет список DTO.
public List<ProductDTO> GetProducts(int categoryID)
{
return (from p in db.Products
where p.CategoryID == categoryID
select new ProductDTO { Name = p.Name }).ToList();
}
, если вы выполняете Linq to Entity
, вы не можете использовать ClassType
с new
в закрытии select
запроса only anonymous types are allowed (new without type)
взглянуть на этот фрагмент моего проекта
//...
var dbQuery = context.Set<Letter>()
.Include(letter => letter.LetterStatus)
.Select(l => new {Title =l.Title,ID = l.ID, LastModificationDate = l.LastModificationDate, DateCreated = l.DateCreated,LetterStatus = new {ID = l.LetterStatusID.Value,NameInArabic = l.LetterStatus.NameInArabic,NameInEnglish = l.LetterStatus.NameInEnglish} })
^^ without type__________________________________________________________________________________________________________^^ without type
из вас добавил new keyword
в закрытии Select даже в complex properties
, вы получите эту ошибку
, поэтому
blockquote>remove
ключевое словоClassTypes from new
Linq to Entity
queries ,,, потому что он преобразуется в sql-оператор и выполняется на SqlServer
, поэтому, когда я могу использовать
new with types
на закрытииselect
?вы можете использовать его, если вы имеете дело с
LINQ to Object (in memory collection)
//opecations in tempList , LINQ to Entities; so we can not use class types in select only anonymous types are allowed var tempList = dbQuery.Skip(10).Take(10).ToList();// this is list of <anonymous type> so we have to convert it so list of <letter> //opecations in list , LINQ to Object; so we can use class types in select list = tempList.Select(l => new Letter{ Title = l.Title, ID = l.ID, LastModificationDate = l.LastModificationDate, DateCreated = l.DateCreated, LetterStatus = new LetterStatus{ ID = l.LetterStatus.ID, NameInArabic = l.LetterStatus.NameInArabic, NameInEnglish = l.LetterStatus.NameInEnglish } }).ToList(); ^^^^^^ with type
после того, как я выполнил
ToList
по запросу, он сталin memory collection
, поэтому мы можем использоватьnew ClassTypes
в выберите
Вот один из способов сделать это, не объявляя класс aditional:
public List<Product> GetProducts(int categoryID)
{
var query = from p in db.Products
where p.CategoryID == categoryID
select new { Name = p.Name };
var products = query.ToList().Select(r => new Product
{
Name = r.Name;
}).ToList();
return products;
}
Однако это нужно использовать, только если вы хотите объединить несколько объектов в одном объекте. Вышеупомянутая функциональность (простое сопоставление продукта с продуктом) выполняется следующим образом:
public List<Product> GetProducts(int categoryID)
{
var query = from p in db.Products
where p.CategoryID == categoryID
select p;
var products = query.ToList();
return products;
}
В ответ на другой вопрос, который был отмечен как дубликат ( см. здесь ), я вычислил быстрое и простое решение, основанное на ответе Сорена:
data.Tasks.AddRange(
data.Task.AsEnumerable().Select(t => new Task{
creator_id = t.ID,
start_date = t.Incident.DateOpened,
end_date = t.Incident.DateCLosed,
product_code = t.Incident.ProductCode
// so on...
})
);
data.SaveChanges();
Примечание. Это решение работает только в том случае, если у вас есть свойство навигации (внешний ключ) в классе Task (здесь называется «Инцидент»). Если у вас этого нет, вы можете использовать одно из других опубликованных решений с помощью «AsQueryable ()».
Вы можете использовать это, и он должен работать.> Вы должны использовать toList
, прежде чем создавать новый список, используя select:
db.Products
.where(x=>x.CategoryID == categoryID).ToList()
.select(x=>new Product { Name = p.Name}).ToList();
Вы можете проецировать в анонимный тип, а затем от него к типу модели
public IEnumerable<Product> GetProducts(int categoryID)
{
return (from p in Context.Set<Product>()
where p.CategoryID == categoryID
select new { Name = p.Name }).ToList()
.Select(x => new Product { Name = x.Name });
}
Редактировать: я собираюсь быть более конкретным, так как этот вопрос получил большое внимание.
Вы не можете напрямую проецироваться в тип модели (ограничение EF), поэтому нет никакого способа обойти это. Единственный способ - проецировать на анонимный тип (1-я итерация), а затем на тип модели (2-я итерация).
Также помните, что при частичной загрузке объектов таким образом они не могут быть обновлены, поэтому они должны оставаться отсоединенными, как они есть.
Я никогда не понимал, почему это невозможно, и ответы на эту тему не дают против этого серьезных оснований (в основном, о частично загруженных данных). Правильно, что в частично загруженном состоянии сущность не может быть обновлена, но тогда этот объект будет отсоединен, поэтому случайные попытки сохранить их будут невозможны.
Рассмотрим метод, который я использовал выше: у нас все еще есть в результате получается частично загруженная модель.
Рассмотрим этот возможный код:
return (from p in Context.Set<Product>()
where p.CategoryID == categoryID
select new Product { Name = p.Name }).AsNoTracking().ToList();
Это также может привести к списку отдельных объектов, поэтому нам не понадобится сделать две итерации. Компилятор был бы умен, чтобы увидеть, что AsNoTracking () используется, что приведет к отсоединенным объектам, чтобы оно могло позволить нам это сделать. Если, однако, AsNoTracking () был опущен, он мог бы сделать то же исключение, что и сейчас, чтобы предупредить нас, что нам нужно быть достаточно конкретным относительно желаемого результата.
вы можете добавить AsEnumerable в свою коллекцию, как показано ниже:
public IQueryable<Product> GetProducts(int categoryID)
{
return from p in db.Products.AsEnumerable()
where p.CategoryID== categoryID
select new Product { Name = p.Name};
}
Вы можете решить эту проблему с помощью объектов передачи данных (DTO).
Это немного похоже на режимы просмотра, в которые вы помещаете нужные вам свойства, и можете их вручную сопоставить в своем контроллере или с помощью третьего -партийные решения, такие как AutoMapper.
С помощью DTO вы можете:
Я изучал это в школе в этом году, и это очень полезный инструмент.
Еще один простой способ:)
public IQueryable<Product> GetProducts(int categoryID)
{
var productList = db.Products
.Where(p => p.CategoryID == categoryID)
.Select(item =>
new Product
{
Name = item.Name
})
.ToList()
.AsQueryable(); // actually it's not useful after "ToList()" :D
return productList;
}
.ToList
в запрос, он будет выполнен и вытащил данные с сервера, то в чем смысл сделать его снова AsQueryable
?.
– Moshii
14 January 2017 в 00:08
Во многих случаях преобразование не требуется. Подумайте по причине, по которой вы хотите строго напечатать List, и оцените, хотите ли вы просто данные, например, в веб-службе или для ее отображения. Это не имеет значения. Вам просто нужно знать, как его читать, и проверить, что это идентично свойствам, определенным в анонимном типе, который вы определили. Это сценарий optimun, вызывающий то, что вам не нужны все поля сущности, и это причина анонимного типа.
Простой способ делает это:
IEnumerable<object> list = dataContext.Table.Select(e => new { MyRequiredField = e.MyRequiredField}).AsEnumerable();
Есть еще один способ, которым я нашел работу, вам нужно построить класс, который происходит из вашего класса Product и использовать его. Например:
public class PseudoProduct : Product { }
public IQueryable<Product> GetProducts(int categoryID)
{
return from p in db.Products
where p.CategoryID== categoryID
select new PseudoProduct() { Name = p.Name};
}
Не уверен, что это разрешено, но оно работает.
Если вы используете фреймворк Entity, попробуйте удалить свойство из DbContext, который использует вашу сложную модель как Entity. У меня была такая же проблема при сопоставлении нескольких моделей в режиме просмотра с именем Entity
public DbSet<Entity> Entities { get; set; }
Удаление записи из DbContext исправил мою ошибку.