Adding custom value in a LINQ join - c#

I have two lists with me:
FXCashFlow [contains - amount, paymentdate, TradeId, Currency]
FXTrades [Contains - TradePreferences, TradeId]
What I need to have in the return class is:
Return Object [Type, amount, paymentdate, TradeId, Currency, TradePreference]
Where Type = "Fx", as the data is fetched from Fx class.
For Return Object, I am using a LINQ JOIN like this:
var list = _fxCashflow.GetAll().Join(_fxTrade.GetAll(),
outerKey => outerKey.TradeId,
innerKey => innerKey.TradeId,
(CashFlow, Trade) => new
{
//"Fx", <- This line gives error
CashFlow.TradeId,
Trade.TradeReference,
CashFlow.PaymentAmount,
CashFlow.CurrencyCode,
CashFlow.PaymentDate,
CashFlow.CashflowTypeCode
}
);
I need to insert "Fx", because this data will be concatenated to a class where this "Fx" will identify the records returning from cashflow class.
How can I insert a custom value in this returning object? Or if there's any other way to do this?
Much Appreciated!!

Try to insert it like this instead:
(CashFlow, Trade) => new
{
Type = "Fx",
CashFlow.TradeId,
Trade.TradeReference,
CashFlow.PaymentAmount,
CashFlow.CurrencyCode,
CashFlow.PaymentDate,
CashFlow.CashflowTypeCode
}

Wouldn't it make more sense to introduce an actual Fx class rather than using a string identifier?
public class Fx
{
public int TradeId { get; set; }
public string TradeRef { get; set; }
public decimal PaymentAmount { get; set; }
...
}
(CashFlow, Trade) => new Fx
{
TradeId = CashFlow.TradeId,
TradeRef = Trade.TradeReference,
PaymentAmount = CashFlow.PaymentAmount,
...
}

You can store this information in enum and use it inside your anonymous object or you can define a new property for the anonymous object.

Related

LINQ join based in interface implemation

Let's say I have a an interface, which is basically a combination of two sub-interfaces. The idea behind this is, that I have two different API's. One which provides public information on a person. And once which provides the 'secret' information. It could look something like this:
public interface IPublicPersonData
{
// The ID is the key
int PersonId { get; set; }
// This property is specific to this part
string Name {get; set; }
}
public interface ISecretPersonData
{
// The ID is the key
int PersonId { get; set; }
// This property is specific to this part
decimal AnnualSalary{ get; set; }
}
public interface IPerson: IPublicPersonData, ISecretPersonData
{
// No new stuff, this is merely a combination of the two.
}
So basically I get two lists. One List<IPublicPersonData> and one List<ISecretPersonData>. I would like to join these into a single List<IPerson>, ideally using LINQ.
I cannot really find anything on how control the type of output from LINQ, based on the type of input, even if the logic is there (in the means of interfaces implementing interfaces).
public List<IPerson> JoinPersonData(
List<IPublicPersonData> publicData,
List<ISecretPersonData> secretData)
{
// What the heck goes here?
}
Say you wrote a method such as:
public ISomething CombinePersonWithSecret(
IPublicPersonData publicPerson,
ISecretPersonData secret)
{
if(publicPerson.PersonId != secret.PersonId)
{
throw ...;
}
//join 2 params into a single entity
return something;
}
Now you might...
IEnumerable<ISomething> secretivePeople = PublicPeople.Join(
SecretPersonData,
publicPerson => publicPerson.PersonId,
secret => secret.PersonId,
(publicPerson, secret) => CombinePersonWithSecret(publicPerson, secret))
The problem is not in the Join, it is in the IPerson you want to return. One of the parameters of the Join methods is used what to do with joined result.
You want to join them into a new object that implements IPerson. If you already have such an object: great, use that one, if you don't have it, here is an easy one:
public PersonData : IPerson // and thus also IPublicPersonData and ISecretPersonData
{
// this PersonData contains both public and secret data:
public IPublicPersonData PublicPersonData {get; set;}
public ISecretPersnData SecretPersonData {get; set;}
// implementation of IPerson / IPublicPersonData / ISecretPersonData
int PersonId
{
get {return this.PublicPersonData.Id; }
set
{ // update both Ids
this.PublicPersonData.Id = value;
this.SecreatPersonData.Id = value;
}
}
public string Name
{
get { return this.PublicPersonData.Name; },
set {this.PublicPersonData.Name = value;}
}
public decimal AnnualSalary
{
get {return this.SecretPersonData.AnnualSalary;},
set {this.SecretPersnData.AnnualSalary = value;
}
}
This object requires no copying of the values of the puclic and secret person data. Keep in mind however, if you change values, the original data is changed. If you don't want this, you'll need to copy the data when creating the object
IEnumerable<IPublicPersonData> publicData = ...
IEnumerable<ISecretPersonData> secretData = ...
// Join these two sequences on same Id. Return as an IPerson
IEnumerable<IPerson> joinedPerson = publicData // take the public data
.Join(secretData, // inner join with secret data
publicPerson => publicPerson.Id, // from every public data take the Id
secretPerson => secretPerson.Id, // from every secret data take the Id
(publicPerson, secretPerson) => new PersonData() // when they match make a new PersonData
{
PublicPersonData = publicPerson,
SecretPersnData = secretPerson,
});
LINQ's Join method does the job for you. Assuming there is a Person : IPerson class, here is two ways to implement your JoinPersonData method:
public static IEnumerable<IPerson> LiteralJoinPersonData(List<IPublicPersonData> publics, List<ISecretPersonData> secrets)
{
return from p in publics
join s in secrets on p.PersonId equals s.PersonId
select new Person(p.PersonId, p.Name, s.AnnualSalary);
}
public static IEnumerable<IPerson> FunctionalJoinPersonData(List<IPublicPersonData> publics, List<ISecretPersonData> secrets)
{
return publics
.Join<IPublicPersonData, ISecretPersonData, int, IPerson>(
secrets,
p => p.PersonId,
s => s.PersonId,
(p, s) => new Person(p.PersonId, p.Name, s.AnnualSalary));
}

How to use a copy-constructor in a LINQ to Entities query?

I'm working on a Linq expression in which I get an object from a DBContext, and I want to make it a custom ViewModel object
my ViewModel receives as parameter an object obtained from the DBContext to work the information and return it completely
This is a little example
public class Obj1 // Object i get from database
{
public int id { get; set; }
public string Param { get; set; }
public string Param2 { get; set; }
public string Random { get; set; }
}
public class Obj2 //ViewModel
{
public string ParamFormateado { get; set; }
public string Random { get; set; }
public Obj2(Obj1 parametro)
{
ParamFormateado = parametro.Param + parametro.Param2;
Random = parametro.Random;
}
}
What I'm trying to do is get an Obj2 with a Linq expression who returns an Obj1 without transforming the information in the linq expression, since in my case it becomes a basically illegible expression
I was try something like this
Obj2 objeto = db.Obj1.Where(x => x.id == "0").Select(x => new Obj2(x)).FirstOrDefault();
Is it possible to perform a Linq query similar to the one I am proposing? since otherwise, I end up having extremely long Linq expressions to format this information, but what would be the best alternative in these cases?
You can't do that because only parameterless constructors are supported. But you can do it with Linq-To-Objects which can be forced with AsEnumerable:
Obj2 objeto = db.Obj1
.Where(x => x.id == "0")
.AsEnumerable() // <--- here
.Select(x => new Obj2(x))
.FirstOrDefault();
So only the filter with Where will be executed in the database, the remaining record(s) are processed in-process.
https://codeblog.jonskeet.uk/2011/01/14/reimplementing-linq-to-objects-part-36-asenumerable/
Dont do it with Linq like that. you have to create a method that takes obj1 as parameter, maps properties and then returns obj2. Or use Automapper from nuget repository.
do it like this
public obj2 Map(obj1 source)
{
var destination = new obj2();
destination.param1 = source.param1;
//
return destination;
}
if you want to pass a collection of objects then do just that and just foreach through the list and return a list of mapped objects. But i would advise you to use Automapper since it automates the proces and you dont have to write a long mapping code.

What Strongly-Typed Data-Structure can I use to hold a collection of multiple RecordSets with different shape

At the request of a responder to my original question here, I have been asked to reword the question in an effort to get to the bottom of the actual requirement.
What Strongly-Typed Data-Structure can I use to hold a collection of multiple RecordSets where each RecordSet will contain rows that may be of a different shape to the other RecordSets?
This need is driven by the need to handle the data coming back from a Stored Procedure via a DbDataReader. The Stored Procedure may have multiple RecordSets, with each RecordSet returning different columns and number of columns.
There will be DTO classes to represent each row of the respective data sets. These are known at compile time. What I need is a data structure that can hold the multiple RecordSets, and for each RecordSet hold the DTOs representing rows returned from the RecordSet.
Example Stored procedure:
CREATE PROCEDURE [dbo].[MultipleRecordSetStoredProcedure]
#Id INT
, #Name VARCHAR(20)
, #Active BIT
, #Price DECIMAL(10, 4)
, #UniqueIdentifier UNIQUEIDENTIFIER
, #Count TINYINT
AS
BEGIN
/* First Record Set */
SELECT
#Id AS Id
, #Name AS Name
UNION
SELECT
17 AS Id
, 'Bill' AS Name;
/* Second Record Set */
SELECT
#Name AS Name,
#Active as Active
UNION
SELECT
'Bill' AS Name
, CAST(0 AS BIT) AS Active;
/* Third Record Set */
SELECT
#UniqueIdentifier AS UNIQUEIDENTIFIER
, #Count AS Count
UNION
SELECT
NEWID() AS UNIQUEIDENTIFIER
, CAST(10 AS TINYINT) AS Count;
END
Example calling code:
DbConnection connection = CreateConnection();
CommandBehavior commandBehavior = CommandBehavior.Default;
// Create a command to execute the stored storedProcedure
using (DbCommand command = connection.CreateStoredProcedureCommand(
procedureName,
procedureParameters,
commandTimeout,
transaction))
{
// Populate a DataReder by calling the command
using (DbDataReader reader = command.ExecuteReader(commandBehavior))
{
// Iterate through each result set...
do
{
// Process the result set line by line
while (reader.Read())
{
// Read data into DataStructure
}
} while (reader.NextResult());
}
}
Example DTOs here:
internal class MultipleRecordSetStoredProcedureReturnType1
{
public int Id { get; set; }
public string Name { get; set; }
}
internal class MultipleRecordSetStoredProcedureReturnType2
{
public bool Active { get; set; }
public decimal Decimal { get; set; }
}
internal class MultipleRecordSetStoredProcedureReturnType3
{
public Guid UniqueIdentifier { get; set; }
public Byte Count { get; set; }
}
Ideally I do not want a list of objects or dynamics but a list of my DTOs for the recordset contents. Hopefully this will better clarify my original question.
In this case, I think it's better to keep things simple.
You have a stored procedure that returns 3 result sets, so create a model that contains those 3 result sets.
To fill your ResultModel, its better to use SqlDataAdapter and DataSet. It make things very simple, very very easier than data reader.
The code for ResultModel:
public class ResultModel
{
public List<Type1> List1 { get; set; }
public List<Type2> List2 { get; set; }
public List<Type3> List3 { get; set; }
}
And I suppose these are your types:
public class Type1
{
public int A { get; set; }
}
public class Type2
{
public int B { get; set; }
public string C { get; set; }
}
public class Type3
{
public int D { get; set; }
public string E { get; set; }
public string F { get; set; }
}
And you can fill your ResultModel, using SqlDataAdapter and DataSet:
public ResultModel GetData()
{
var connection = #"data source=(localdb)\v11.0;initial catalog=TestDB;integrated security=True;MultipleActiveResultSets=True;";
var command = "dbo.Procedure";
var tableAdapter = new System.Data.SqlClient.SqlDataAdapter(command, connection);
tableAdapter.SelectCommand.CommandType = CommandType.StoredProcedure;
var dataSet = new DataSet();
tableAdapter.Fill(dataSet);
var t1 = dataSet.Tables[0].Rows.Cast<DataRow>()
.ToList().Select(row => new Type1
{
A = row.Field<int>("A"),
}).ToList();
var t2 = dataSet.Tables[1].Rows.Cast<DataRow>()
.ToList().Select(row => new Type2
{
B = row.Field<int>("B"),
C = row.Field<string>("C")
}).ToList();
var t3 = dataSet.Tables[1].Rows.Cast<DataRow>()
.ToList().Select(row => new Type3
{
D = row.Field<int>("D"),
E = row.Field<string>("E"),
F = row.Field<string>("F")
}).ToList();
var result = new ResultModel() { List1 = t1, List2 = t2, List3 = t3 };
return result;
}
The key points here are:
We have a clean and simple ResultModel
Using SqlDataAdapter and a DataSet makes reading multiple result so easy.
Using Cast<DataRow>() enables us to use Linq against DataTable.Rows
Using Field<T>("field") enables us to get typed value of field
I'm not sure it makes sense to return a List containing disparate results. I'd probably create a wrapper class to group your dto objects like below.
public class RecordSetContainer
{
public RecordSetContainer()
{
RecordSet1 = new List<MultipleRecordSetStoredProcedureReturnType1>();
RecordSet2 = new List<MultipleRecordSetStoredProcedureReturnType2>();
RecordSet3 = new List<MultipleRecordSetStoredProcedureReturnType3>();
}
public List<MultipleRecordSetStoredProcedureReturnType1> RecordSet1 { get; set; }
public List<MultipleRecordSetStoredProcedureReturnType2> RecordSet2 { get; set; }
public List<MultipleRecordSetStoredProcedureReturnType3> RecordSet3 { get; set; }
}
If you wanted to take the db code a step further to make it generic you could do something along these lines.
public T CallMultipleRecordSetStoredProcedure<T>(
params Expression<Func<T, IList>>[] recordSetPropertiesInOrder)
where T : class, new()
{
var outputType = typeof (T);
var output = new T();
// DbConnection & Command setup hidden
var recordSetNumber = 0;
do
{
var outputRecordSetPropertyName =
((MemberExpression) recordSetPropertiesInOrder[recordSetNumber].Body).Member.Name;
var dtoList = (IList) outputType.GetProperty(outputRecordSetPropertyName).GetValue(output);
var dtoListType = dtoList.GetType().GetGenericArguments()[0];
while (reader.Read())
{
var item = Activator.CreateInstance(dtoListType);
var propertiesToWrite = dtoListType.GetProperties().Where(p => p.CanWrite);
foreach (var property in propertiesToWrite)
{
property.SetValue(
item,
Convert.ChangeType(reader[property.Name], property.PropertyType));
}
dtoList.Add(item);
}
recordSetNumber++;
} while (reader.NextResult());
return output;
}
Not the prettiest or readable code I admit but it should allow you to call any multi record set stored procedure as long as the property names match the column names. One downside with this code is that while the compiler will enforce you to only select IList properties in you expressions it is unable to ensure you pick a generic list (which the method itself actually requires).
For your example case the method would be called as below
CallMultipleRecordSetStoredProcedure<RecordSetContainer>(
rsc => rsc.RecordSet1,
rsc => rsc.RecordSet2,
rsc => rsc.RecordSet3);
Having read the original question, and this one, it sounds like you will ultimately end up with a List that contains within it other Lists each with their own type. As you iterate through the list you'll have no idea of what type to expect for the inner list, as it's variable. Given this you'll inevitably have to test for the type and then cast it, e.g.
foreach(var resultset in resultsets)
{
if(resultset is MultipleRecordSetStoredProcedureReturnType1)
//... cast it and do something...
}
Given that you'll inevitably have to test for the inner type and cast, even if you could achieve your goal I'm not sure it will serve any purpose in the end. The list may as well just be
List<List<Object>>
or perhaps
List<List<IResultSet>>
As per the final example, you could consider defining an Interface for the inner type just to ensure that only objects that inherit from that interface are contained within it. This may be beneficial even if the interface doesn't define any behaviour and is just a simple declaration.

Member is "not supported in LINQ to Entities"

So I am new to C#, LINQ, and MVC. I am trying to get a list of Ages, but it says
The specified type member 'Age' is not supported in LINQ to Entities.
Only initializers, entity members, and entity navigation properties
are supported.
For a previous tutorial, they use this exact same logic, except they check a string, not an int (Age). Why is this giving me a fit, and how can I fix it?
public ActionResult SearchIndex(string ageValue, string searchString)
{
if (!string.IsNullOrEmpty(ageValue))
{
var AgeList = new List<string>();
var AgeListQry = from d in db.Actors orderby d.Age select d.Age.ToString();
AgeList.AddRange(AgeListQry.Distinct());
}
// other stuff
}
I want to learn what is going on, so that I can avoid this in the future!
Entity Model code
public class Actor
{
public int ID { get; set; }
public string Name { get; set; }
public DateTime BirthDate { get; set; }
public int Age
{
get {
return (int)(DateTime.Now - BirthDate).TotalDays / 365;
}
}
public decimal NetValue { get; set; }
}
public class ActorDBContext : DbContext
{
public DbSet<Actor> Actors { get; set; }
}
As mentioned in the comments, you can't call ToString() in a Linq to Entities query. Instead do it like this:
var AgeList = new List<string>();
//retrieve as whatever type Age is, no conversion in SQL Server
var AgeListQry = (from d in db.Actors orderby d.Age select d.Age).ToList();
//convert them after the fact, using Linq to Objects
AgeList.AddRange(AgeListQry.Select(a => a.ToString()).Distinct());
EDIT
I saw your latest update that does show that Age is not a database column. You are then required to do something like this (assuming BirthDate is properly mapped):
var AgeList = new List<string>();
//retrieve BirthDate from SQL Server and use ToList() to get it to run immediately
var AgeListQry = (from d in db.Actors orderby d.BirthDate select d.BirthDate).ToList();
//convert them after the fact, using Linq to Objects
AgeList.AddRange(AgeListQry.Select(bd => ((int)(DateTime.Now - bd).TotalDays / 365).ToString()).Distinct());
Linq to Entities maps your expressions to SQL statements and there is nothing for it to map to when you use your Age property. Instead, you need to get what you can from SQL Server (BirthDate) and then do the translation to Age yourself. You could replace the inline code with a method call like this if you'd rather:
AgeList.AddRange(AgeListQry.Select(bd => CalculateAge(bd)).Distinct());
//...
private string CalculateAge(DateTime birthday)
{
return ((int)(DateTime.Now - bd).TotalDays / 365).ToString();
}
You haven't the Age in you DB scheme and it is impossible to convert LINQ to DB query.
You must order the Age collection in client side or add calculated column to your table.
There is another way. Have a converter file, where you pass the object, works with the birthdate and produces the age, returns the same object. That also means, that you can't search the database for the age column

C# convert object in a list to another object

Is it possible to assign list of objects to another list of objects that takes it as a constructor?
Eg.
public class PersonORM{
public PersonORM(Person p){ /* convert */ }
public int PersonId { get; set; }
/* Other properties here */
}
public class Person{
public int PersonId { get; set; }
/* Other properties here */
}
How do I convert Person to PersonORM using the constructor when they are in a list like this:
List<Person> people = getPeople();
List<PersonORM> peopleOrm = new List<Person>(people); // Is something like this possoble?
It is not possible to do that with the syntax you have as the constructor of List<T> does not support it.
If you can use linq (depending on which version of .Net you are targeting), you can do this:
List<PersonORM> personOrm = people.Select(p => new PersonORM(p)).ToList();
This uses the Select operator to perform the conversion from each item in the original list.
It can be done using LINQ:
List<PersonORM> peopleOrm = new List<Person>(people.Select(p => new PersonORM(p)));

Categories