J'ai cette erreur dans cette expression linq:
var naleznosci = (from nalTmp in db.Naleznosci
where nalTmp.idDziecko == idDziec
select new Payments
(
nalTmp.Dziecko.Imie,
nalTmp.Dziecko.Nazwisko,
nalTmp.Miesiace.Nazwa,
nalTmp.Kwota,
nalTmp.RodzajeOplat.NazwaRodzajuOplaty,
nalTmp.RodzajeOplat.TypyOplat.NazwaTypuOplaty,
nalTmp.DataRozliczenia,
nalTmp.TerminPlatnosci
)).ToList();
Une idée de comment résoudre ce problème? J'essaye avec n'importe quelle combinaison d'expression ...: /
sans plus d'informations sur 'Paiements', cela n'aidera pas grand chose, mais si vous voulez créer un objet Payments et définir certaines de ses propriétés en fonction des valeurs de colonne:
var naleznosci = (from nalTmp in db.Naleznosci
where nalTmp.idDziecko == idDziec
select new Payments
{
Imie = nalTmp.Dziecko.Imie,
Nazwisko = nalTmp.Dziecko.Nazwisko,
Nazwa= nalTmp.Miesiace.Nazwa,
Kwota = nalTmp.Kwota,
NazwaRodzajuOplaty = nalTmp.RodzajeOplat.NazwaRodzajuOplaty,
NazwaTypuOplaty = nalTmp.RodzajeOplat.TypyOplat.NazwaTypuOplaty,
DataRozliczenia = nalTmp.DataRozliczenia,
TerminPlatnosci = nalTmp.TerminPlatnosci,
}).ToList();
Si vous souhaitez toujours utiliser votre constructeur pour l'initialisation et non des propriétés (ce comportement est parfois souhaité à des fins d'initialisation), énumérez la requête en appelant ToList()
ou ToArray()
, puis utilisez Select(…)
. Ainsi, il utilisera LINQ to Collections et cette limitation de l'impossibilité d'appeler un constructeur avec des paramètres dans Select(…)
disparaîtra.
Donc, votre code devrait ressembler à quelque chose comme ça:
var naleznosci = db.Naleznosci
.Where(nalTmp => nalTmp.idDziecko == idDziec)
.ToList() // Here comes transfer to LINQ to Collections.
.Select(nalImp => new Payments
(
nalTmp.Dziecko.Imie,
nalTmp.Dziecko.Nazwisko,
nalTmp.Miesiace.Nazwa,
nalTmp.Kwota,
nalTmp.RodzajeOplat.NazwaRodzajuOplaty,
nalTmp.RodzajeOplat.TypyOplat.NazwaTypuOplaty,
nalTmp.DataRozliczenia,
nalTmp.TerminPlatnosci
))
.ToList();
Ayant moi-même rencontré cette erreur, j'ai pensé ajouter que si le type Payment
est un struct
, vous rencontriez également la même erreur car les types struct
ne prennent pas en charge les constructeurs sans paramètre.
Dans ce cas, la conversion de Payment
en classe et l'utilisation de la syntaxe d'initialisation d'objet résoudront le problème.
Si vous êtes comme moi et ne voulez pas avoir à renseigner vos propriétés pour chaque requête que vous créez, il existe un autre moyen de résoudre ce problème.
var query = from orderDetail in context.OrderDetails
join order in context.Orders on order.OrderId equals orderDetail.orderId
select new { order, orderDetail };
À ce stade, vous avez un IQueryable contenant un objet anonyme. Si vous voulez remplir votre objet personnalisé avec un constructeur, vous pouvez simplement faire quelque chose comme ceci:
return query.ToList().Select(r => new OrderDetails(r.order, r.orderDetail));
Désormais, votre objet personnalisé (qui prend deux objets en paramètre) peut renseigner vos propriétés à votre guise.
D'abord, j'éviterais la solution avec
from ....
select new Payments
{
Imie = nalTmp.Dziecko.Imie,
....
}
Cela nécessite un constructeur vide et ignore l'encapsulation. Par conséquent, vous indiquez que new Payments () est un paiement valide sans données, mais l'objet doit au moins comporter une valeur et probablement d'autres champs obligatoires, selon votre domaine.
Il est préférable d'avoir un constructeur pour les champs obligatoires mais d'apporter uniquement les données nécessaires:
from ....
select new
{
Imie = nalTmp.Dziecko.Imie,
Nazwisko = nalTmp.Dziecko.Nazwisko
....
}
.ToList() // Here comes transfer to LINQ to Collections.
.Select(nalImp => new Payments
(
nalTmp.Imie,//assume this is a required field
...........
)
{
Nazwisko = nalTmp.Nazwisko //optional field
})
.ToList();
Juste ToList()
la DbSet
avant l'instruction Select
.. La DbSet
réelle est enregistrée en tant que requête, elle n'est pas encore remplie .. Après avoir appelé ToList()
, vous jouez avec des objets et vous pouvez utiliser un constructeur autre que celui par défaut dans la requête.
Ce n'est pas le moyen le plus efficace en termes de temps d'utilisation, mais c'est une option pour les petits ensembles.
Vous pouvez essayer de faire la même chose, mais en utilisant les méthodes d’extension. Quel est le fournisseur de la base de données utilisée?
var naleznosci = db.Naleznosci
.Where<TSource>(nalTmp => nalTmp.idDziecko == idDziec)
.Select<TSource, TResult>(
delegate(TSource nalTmp) { return new Payments
(
nalTmp.Dziecko.Imie,
nalTmp.Dziecko.Nazwisko,
nalTmp.Miesiace.Nazwa,
nalTmp.Kwota,
nalTmp.RodzajeOplat.NazwaRodzajuOplaty,
nalTmp.RodzajeOplat.TypyOplat.NazwaTypuOplaty,
nalTmp.DataRozliczenia,
nalTmp.TerminPlatnosci
); })
.ToList();
J'ai eu le même problème aujourd'hui et ma solution était similaire à celle décrite par Yoda, mais elle ne fonctionne que dans une syntaxe fluide.
Adapter ma solution à votre code: J'ai ajouté la méthode statique suivante à la classe d'objet
/// <summary>
/// use this instead of a parameritized constructor when you need support
/// for LINQ to entities (fluent syntax only)
/// </summary>
/// <returns></returns>
public static Func<Naleznosci, Payments> Initializer()
{
return n => new Payments
{
Imie = n.Dziecko.Imie,
Nazwisko = n.Dziecko.Nazwisko,
Nazwa = n.Miesiace.Nazwa,
Kwota = n.Kwota,
NazwaRodzajuOplaty = n.RodzajeOplat.NazwaRodzajuOplaty,
NazwaTypuOplaty = n.RodzajeOplat.TypyOplat.NazwaTypuOplaty,
DataRozliczenia = n.DataRozliczenia,
TerminPlatnosc = n.TerminPlatnosci
};
}
puis mis à jour la requête de base comme suit:
var naleznosci = (from nalTmp in db.Naleznosci
where nalTmp.idDziecko == idDziec
select new Payments.Initializer());
Ceci est logiquement équivalent à la solution de James Manning avec l'avantage de pousser le bloc d'initialisation de membre vers l'objet de transfert de classe/données
Remarque: À l’origine, j’utilisais des noms plus descriptifs que "Initializer" Mais après avoir examiné comment je l’utilisais, j’ai trouvé que "Initilizer" était suffisant (du moins pour mes besoins).
Note finale:
Après avoir proposé cette solution, je pensais à l’origine qu’il serait simple de partager le même code et de l’adapter à la syntaxe Query. Je ne crois plus que ce soit le cas. Je pense que si vous voulez pouvoir utiliser ce type de construction abrégée, vous aurez besoin d'une méthode pour chaque fluent (requête, fluent) tel que décrit ci-dessus, pouvant exister dans la classe d'objet elle-même.
Pour la syntaxe de requête, une méthode d'extension (ou une méthode en dehors de la classe de base utilisée) serait requise. (puisque la syntaxe de la requête veut utiliser un IQueryable plutôt que T)
Voici un exemple de ce que j’avais utilisé pour que cela fonctionne enfin avec la syntaxe de requête. (Yoda l'a déjà cloué, mais je pense que l'utilisation pourrait être plus claire car je ne l'ai pas eu au début)
/// <summary>
/// use this instead of a parameritized constructor when you need support
/// for LINQ to entities (query syntax only)
/// </summary>
/// <returns></returns>
public static IQueryable<Payments> Initializer(this IQueryable<Naleznosci> source)
{
return source.Select(
n => new Payments
{
Imie = n.Dziecko.Imie,
Nazwisko = n.Dziecko.Nazwisko,
Nazwa = n.Miesiace.Nazwa,
Kwota = n.Kwota,
NazwaRodzajuOplaty = n.RodzajeOplat.NazwaRodzajuOplaty,
NazwaTypuOplaty = n.RodzajeOplat.TypyOplat.NazwaTypuOplaty,
DataRozliczenia = n.DataRozliczenia,
TerminPlatnosc = n.TerminPlatnosci
};
}
et l'usage
var naleznosci = (from nalTmp in db.Naleznosci
where nalTmp.idDziecko == idDziec
select nalTmp).Initializer().ToList();
Désolé d’être en retard pour la soirée, mais après avoir trouvé ceci , j’ai pensé que cela devrait être partagé, car c’est la mise en œuvre la plus propre, la plus rapide et la plus économisante en mémoire que je puisse trouver.
Adapté à votre exemple, vous écririez:
public static IQueryable<Payments> ToPayments(this IQueryable<Naleznosci> source)
{
Expression<Func<Naleznosci, Payments>> createPayments = naleznosci => new Payments
{
Imie = source.Dziecko.Imie,
Nazwisko = source.Dziecko.Nazwisko,
Nazwa= source.Miesiace.Nazwa,
Kwota = source.Kwota,
NazwaRodzajuOplaty = source.RodzajeOplat.NazwaRodzajuOplaty,
NazwaTypuOplaty = source.RodzajeOplat.TypyOplat.NazwaTypuOplaty,
DataRozliczenia = source.DataRozliczenia,
TerminPlatnosci = source.TerminPlatnosci,
};
return source.Select(createPayments);
}
Les gros avantages ici (comme Damien Guard l'a souligné dans les commentaires sur le lien) sont les suivants:
var foo = createPayments(bar);
ainsi que l'utilisation via myIQueryable.ToPayments () sont possibles.yeh, essayez comme ça ....
var naleznosci = (from nalTmp in db.Naleznosci
where nalTmp.idDziecko == idDziec
select new Payments()
{
Dziecko.Imie,
Dziecko.Nazwisko,
Miesiace.Nazwa,
Kwota,
RodzajeOplat.NazwaRodzajuOplaty,
RodzajeOplat.TypyOplat.NazwaTypuOplaty,
DataRozliczenia,
TerminPlatnosci
}).ToList();
cela créera votre objet Paiement à l'aide d'un constructeur sans paramètre, puis initialisera les propriétés répertoriées à l'intérieur des accolades { }
De plus, si vous souhaitez utiliser un constructeur avec plusieurs objets à initialiser, vous risquez d'obtenir une erreur si aucune valeur n'est renvoyée par Linq.
Donc, vous voudrez peut-être faire quelque chose comme ceci:
(from x in table_1
join y in table_2
on x.id equals y.id
select new {
val1 = x,
val2 = y
})
.DefaultIfEmpty()
.ToList()
.Select(a => new Val_Constructor(a.val1 != null ? a.val1 : new Val_1_Constructor(),
a.val2 != null ? a.val2 : new Val_2_Constructor()))
.ToList();
En plus des méthodes susmentionnées, vous pouvez également l'analyser en tant que collection Enumerable, comme suit:
(from x in table
....
).AsEnumerable()
.Select(x => ...)
Cela présente également l'avantage de rendre la vie plus facile lors de la création d'un objet anonyme, comme ceci:
(from x in tableName
select x.obj)
.Where(x => x.id != null)
.AsEnumerable()
.Select(x => new {
objectOne = new ObjectName(x.property1, x.property2),
parentObj = x
})
.ToList();
Cependant, vous vous souviendrez qu'analyser une collection en tant que Enumerable la récupère en mémoire et nécessite donc beaucoup de ressources! La prudence devrait être utilisée ici.
Même s'il est tard pour répondre, cela pourrait quand même aider une personne en détresse. Étant donné que LINQ to entity ne prend pas en charge les constructions d'objet sans paramètre. Cependant, les méthodes de projection pour IEnumerable.
Donc, avant la sélection, il suffit de convertir votre IQueryable à IEnumerable en utilisant ce code:
var result = myContext.SomeModelClass.AsEnumerable().Select(m => m.ToString());
Cela fonctionnera bien. Cependant, il perdra bien entendu les avantages des requêtes natives.