I have two lists:
List1 = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K' }
List2 = { 'B', 'C', 'D' }
List1 is all the columns in a table and List2 are the columns that make up a foreign or primary key on that same table.
In this example, 'A', 'B', 'C' and 'D' are a primary key of a table. 'B', 'C' and 'D' are a foreign key of the same table. 'G' and 'H' are two columns of a table I don't want to include.
I can't seem to be able to write a LINQ statement that produces this:
List3 = { 'B', 'C', 'D', 'E', 'F', 'I', 'J', 'K' }
List3 is a list of the parameters I want to give to an "UPDATE" stored procedure I am generating. List2 + 'K' will be my "WHERE"; 'E', 'F', 'I' and 'J' will be the columns the procedure will use in the "SET".
Both List1 and List2 will be different every time the LINQ is executed.
All lists are of type List where DbColumn is defined as:
public class DbColumn
{
public string Name { get; set; }
//public bool IsPrimaryKey { get; set; }
//public bool IsForeignKey { get; set; }
public int OrdinalPosition { get; set; }
public string DataType { get; set; }
public int CharMaxLength { get; set; }
public bool AllowNulls { get; set; }
public static DbColumn Create(string name, int ordinal_position, string data_type, int charMaxLength, string is_nullable)
{
DbColumn column = new DbColumn();
column.Name = name;
//column.IsPrimaryKey = isPk;
//column.IsForeignKey = isFk;
column.OrdinalPosition = ordinal_position;
column.DataType = data_type;
column.CharMaxLength = charMaxLength;
if (!String.IsNullOrEmpty(is_nullable))
column.AllowNulls = is_nullable.ToUpper() == "YES" ? true : false;
else
column.AllowNulls = false;
return column;
}
public override string ToString()
{
return Name;
}
}
Columns can be part of DbConstraint and DbTable. DbTable also has DbConstraint as a properties:
public class DbTable
{
public string Name { get; set; }
public string Catalog { get; set; }
public string Schema { get; set; }
public List<DbColumn> Columns { get; set; }
public DbSProc Insert { get; set; }
public DbSProc Update { get; set; }
public DbSProc Delete { get; set; }
public List<DbSProc> ReadProcedures { get; set; }
public List<DbConstraint> Constraints { get; set; }
public static DbTable Create(string name, string catalog, string schema, List<DbColumn> columns)
{
DbTable table = new DbTable();
table.Catalog = catalog;
table.Schema = schema;
table.Name = name;
table.Columns = columns;
table.ReadProcedures = new List<DbSProc>();
return table;
}
public override string ToString()
{
return Name;
}
}
public class DbConstraint
{
public string Name { get; set; }
public bool IsPrimary { get; set; }
public List<DbColumn> Columns { get; set; }
public static DbConstraint Create(string name, bool isPrimary)
{
DbConstraint constraint = new DbConstraint();
constraint.Name = name;
constraint.IsPrimary = isPrimary;
constraint.Columns = new List<DbColumn>();
return constraint;
}
public override string ToString()
{
return Name;
}
}
The goal of the LINQ statement is to select for parameters only those columns that are necessary for the "WHERE" piece (e.g.: a foreign/primary key plus "_VerCol") and those necessary for the "SET" piece (non-primary keys).
You can find the code on CodePlex: https://sqlmeth.codeplex.com.
Can anybody help me please?
Thank you!
I assume you know the characters you want to exclude.
List<char> a = new List<char>() { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K' };
List<char> b = new List<char>() { 'B', 'C', 'D' };
List<char> exclusionList = new List<char> {'A','G', 'H'};
List<char> c = a.Select(x => x).Where(x => !exclusionList.Contains(x)).ToList();
Related
I am trying to join results from three linq queries. The types are as follows:
orderItems is a List<OrderLineItem>
transitTimes is a Dictionary<int,int> where Key = SiteId and Value = TransitDays
shippingPriority is a Dictionary<int,int> where Key = DefaultPriority and Value = SiteId
public class OrderLineItem
{
public decimal OrderLineWorkId { get; set; }
public string Sku { get; set; }
public string SiteId { get; set; }
public char FlagSlapType { get; set; }
public char FlagTruck { get; set; }
public string SkuType { get; set; }
public int QtyOrdered { get; set; }
public int QtySellable { get; set; }
}
public class OrderAllocation
{
public int SiteId { get; set; }
public int TransitDays { get; set; }
public int QtyItemsInStock { get; set; }
public int QtyParcelInStock { get; set; }
public int DefaultPriority { get; set; }
}
Here is my linq query, but it always returns 0 results. Not sure where I am going wrong?
var results = (from i in orderItems
join t in transitTimes on i.SiteId equals t.Key.ToString()
join d in shippingPriority on t.Key equals d.Value
group i by i.SiteId into g
select new OrderAllocation()
{
SiteId = Convert.ToInt32(g.Key),
TransitDays = transitTimes.Select(x => x.Value).FirstOrDefault(),
QtyItemsInStock = g.Count(e => e.QtySellable >= e.QtyOrdered),
QtyParcelInStock = g.Count(e => e.QtySellable >= e.QtyOrdered && e.FlagSlapType != 'Y'),
DefaultPriority = defaultShippingPriority.Select(x => x.Key).FirstOrDefault()
}).OrderBy(x => x.SiteId).ToList();
UPDATE
I found what was wrong, the SiteId of type string had a values with a prefix 0 (ie 01, 02, etc) and therefore would not join with values like 1, 2, etc. Changed type from string to int and am now getting results. Sorry for the false alarm.
The issue may be related to differences in the data types:
(from i in orderItems
join t in transitTimes on i.SiteId equals t.Key.ToString()
orderItems defines SiteId as an string
public string SiteId { get; set; }
while transitTimes has a key of int
Dictionary<int,int>
The join condition of int to string may not provide the results you are expecting.
public class EmpModel
{
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public Gender Gender { get; set; }
public int DepartmentId { get; set; }
}
#region [ Enumeration]
public enum Gender
{
Male = 0,
FeMale = 1
}
Now how to get enum value
var employees = root.Elements("Employee");
foreach (var element in employees)
{
var employee = new EmpModel
{
UserName = element.Element("UserName").Value,
FirstName = element.Element("FirstName").Value,
LastName=element.Element("LastName").Value,
Age=Convert.ToInt32( element.Element("Age").Value),
Gender= element.Element("Gender").Value, // On this line shows error
DepartmentId=Convert.ToInt32(element.Element("Department").Value)
};
Thanks
Enumerations in C# are represented by integers (Int32) internally by default. So in this case, if your XML file contains the string "0" or "1", you can simply parse it and then cast it the the correct enum type:
Gender = (Gender) Int32.Parse(element.Element("Gender").Value);
If you are reading strings that correspond to the names of the Enumeration, you should use Enum.Parse():
Gender = (Gender) Enum.Parse(typeof(Gender), element.Element("Gender").Value);
Below is the code I am using and the database table it is pulling from has about 92000 records in it. The way it is pulling right now it is pulling all 92000 records then doing the filtering.
What I am looking to do is the filtering on the initial pull from the DB so that it does not take aproximately 40 seconds to load the page.
This is something I am still new at so I am lost as to how to do this and make it work with my view
public ViewResult Makes()
{
var items = (from item in DBCacheHelper.recallslist
orderby item.MFGTXT ascending
select item.ToDomainRecall()).GroupBy(item => item.MFGTXT).Select(grp => grp.First());
return View(items);
}
public static IEnumerable<Recall> recallslist
{
get
{
if (c["GetAllRecalls"] == null)
{
c.Insert("GetAllRecalls", GetAllRecalls());
return (IEnumerable<Recall>)c["GetAllRecalls"];
}
else
{
return (IEnumerable<Recall>)c["GetAllRecalls"];
}
}
}
public static IEnumerable<Recall> GetAllRecalls()
{
using (DealerContext context = new DealerContext())
{
var items = from item in context.recalls.ToList<Recall>()
select item.ToDomainRecall();
return items.ToList<Recall>();
}
}
SELECT
[Extent1].[RecallsId] AS [RecallsId],
[Extent1].[RECORD_ID] AS [RECORD_ID],
[Extent1].[CAMPNO] AS [CAMPNO],
[Extent1].[MAKETXT] AS [MAKETXT],
[Extent1].[MODELTXT] AS [MODELTXT],
[Extent1].[YEARTXT] AS [YEARTXT],
[Extent1].[MFGCAMPNO] AS [MFGCAMPNO],
[Extent1].[COMPNAME] AS [COMPNAME],
[Extent1].[MFGNAME] AS [MFGNAME],
[Extent1].[BGMAN] AS [BGMAN],
[Extent1].[ENDMAN] AS [ENDMAN],
[Extent1].[RCLTYPECD] AS [RCLTYPECD],
[Extent1].[POTAFF] AS [POTAFF],
[Extent1].[ODATE] AS [ODATE],
[Extent1].[INFLUENCED_BY] AS [INFLUENCED_BY],
[Extent1].[MFGTXT] AS [MFGTXT],
[Extent1].[RCDATE] AS [RCDATE],
[Extent1].[DATEA] AS [DATEA],
[Extent1].[RPNO] AS [RPNO],
[Extent1].[FMVSS] AS [FMVSS],
[Extent1].[DESC_DEFECT] AS [DESC_DEFECT],
[Extent1].[CONEQUENCE_DEFECT] AS [CONEQUENCE_DEFECT],
[Extent1].[CORRECTIVE_ACTION] AS [CORRECTIVE_ACTION],
[Extent1].[NOTES] AS [NOTES],
[Extent1].[RCL_CMPT_ID] AS [RCL_CMPT_ID]
FROM [dbo].[Recalls] AS [Extent1]
Update:
Ultimately I would like to only pull records from the Recalls Table where the MFGTXT is equal to the
MakeName in the AutoMake Table
public class AutoMake
{
[Key]
public int MakeID { get; set; }
public string MakeName { get; set; }
public AutoMake ToDomainAutoMakes()
{
return new AutoMake
{
MakeID = this.MakeID,
MakeName = this.MakeName
};
}
}
public class Recall
{
[Key]
public int RecallsId { get; set; }
public string RECORD_ID { get; set; }
public string CAMPNO { get; set; }
public string MAKETXT { get; set; }
public string MODELTXT { get; set; }
public string YEARTXT { get; set; }
public string MFGCAMPNO { get; set; }
public string COMPNAME { get; set; }
public string MFGNAME { get; set; }
public string BGMAN { get; set; }
public string ENDMAN { get; set; }
public string RCLTYPECD { get; set; }
public string POTAFF { get; set; }
public string ODATE { get; set; }
public string INFLUENCED_BY { get; set; }
public string MFGTXT { get; set; }
public string RCDATE { get; set; }
public string DATEA { get; set; }
public string RPNO { get; set; }
public string FMVSS { get; set; }
public string DESC_DEFECT { get; set; }
public string CONEQUENCE_DEFECT { get; set; }
public string CORRECTIVE_ACTION { get; set; }
public string NOTES { get; set; }
public string RCL_CMPT_ID { get; set; }
public Recall ToDomainRecall()
{
return new Recall
{
RECORD_ID = this.RECORD_ID,
CAMPNO = this.CAMPNO,
MAKETXT = this.MAKETXT,
MODELTXT = this.MODELTXT,
YEARTXT = this.YEARTXT,
MFGCAMPNO = this.MFGCAMPNO,
COMPNAME = this.COMPNAME,
MFGNAME = this.MFGNAME,
BGMAN = this.BGMAN,
ENDMAN = this.ENDMAN,
RCLTYPECD = this.RCLTYPECD,
POTAFF = this.POTAFF,
ODATE = this.ODATE,
INFLUENCED_BY = this.INFLUENCED_BY,
MFGTXT = this.MFGTXT,
RCDATE = this.RCDATE,
DATEA = this.DATEA,
RPNO = this.RPNO,
FMVSS = this.FMVSS,
DESC_DEFECT = this.DESC_DEFECT,
CONEQUENCE_DEFECT = this.CONEQUENCE_DEFECT,
CORRECTIVE_ACTION = this.CORRECTIVE_ACTION,
NOTES = this.NOTES,
RCL_CMPT_ID = this.RCL_CMPT_ID
};
}
}
If you want to add server side filtering outside of your repository methods, you need to return your types as IQueryable rather than IEnumerable and not call .ToList, .AsEnumerable, or any other method that would cause .GetEnumerator to be called. Additionally, your cast `(IEnumerable)c["GetAllRecalls"];' forces LINQ to Objects to be used for subsequent requests rather than retaining the expression tree and using Entity Framework. That being said, you may need to move your call to ToDomainRecall method to after the additional filter is applied as well because that can't be translated to your database. Here are some of the changes you would need to make:
public ViewResult Makes()
{
var items = (from item in DBCacheHelper.recallslist
orderby item.MFGTXT ascending
select item.ToDomainRecall()).GroupBy(item => item.MFGTXT).Select(grp => grp.First());
return View(items);
}
public static IQueryable<Recall> recallslist
{
get
{
if (c["GetAllRecalls"] == null)
{
c.Insert("GetAllRecalls", GetAllRecalls(context));
}
return c["GetAllRecalls"];
}
}
public static IQueryable<Recall> GetAllRecalls(DealerContext context)
{
var items = context.recalls;
return items;
}
Looks like your DBaccess is done in the call to DBCacheHelper.recallslist.
You need to edit the sql that runs from/in this function.
As Eranga pointed out, you don't show how you are filtering the large number down to a smaller number of records. I assume you want 20 or 100 at a time? If so, please see the accepted answer here:
efficient way to implement paging
Specifically, this part which shows how to only retrieve rows x to y (where x = #p0 + 1 AND y = #p0 + #p1):
SELECT [t1].[CodCity],
[t1].[CodCountry],
[t1].[CodRegion],
[t1].[Name],
[t1].[Code]
FROM (
SELECT ROW_NUMBER() OVER (
ORDER BY [t0].[CodCity],
[t0].[CodCountry],
[t0].[CodRegion],
[t0].[Name],
[t0].[Code]) AS [ROW_NUMBER],
[t0].[CodCity],
[t0].[CodCountry],
[t0].[CodRegion],
[t0].[Name],
[t0].[Code]
FROM [dbo].[MtCity] AS [t0]
) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN #p0 + 1 AND #p0 + #p1
ORDER BY [t1].[ROW_NUMBER]
I am trying to concat and comma deliminated (or space) a list and project it. I have some sample code below.
public class Friend
{
public string Name { get; set; }
}
public class Person
{
public int PersonID { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
List<Friend> Friends { get; set; }
}
public class ProjectedPerson
{
public int PersonID { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
public string FriendsList { get; set; }
}
public class Test
{
public void MyTest()
{
var query = from p in MyDataStore.Person
select p;
var results = from q in query
select new ProjectedPerson
{
PersonID = q.PersonID,
FirstName = q.FirstName,
Surname = q.Surname,
FriendsList = q.FriendsList.Concat() //??? How can I concat this and return a string
};
}
}
Use string.Join (note that the list will need to be in memory first), to concatentate the selected properties from your Friend objects. If you are using .NET 3.5, you'll need to use ToArray() as well as the overloads on string.Join in 3.5 require an array.
var query = (from p in MyDataStore.Person
select p).ToList(); // <-- bring into memory with ToList()
var results = from q in query
select new ProjectedPerson
{
PersonID = q.PersonID,
FirstName = q.FirstName,
Surname = q.Surname,
FriendsList = string.Join( ", ", q.Friends.Select( f => f.Name ) )
};
string.Join is the better way but abusing LINQ is just so fun.
var query = (from p in MyDataStore.Person
select p).ToList(); // <-- bring into memory with ToList()
var results = from q in query
select new ProjectedPerson
{
PersonID = q.PersonID,
FirstName = q.FirstName,
Surname = q.Surname,
FriendsList = q.Friends.Aggregate<Friend, string>(null, (accum, f) => accum + (accum == null ? accum : ", ") + f.Name)
};
I have two list of different columns, but each list have a common column with the same key, how do I combine them into a new list, i.e:
public class TradeBalanceBreak
{
public int CommID { get; set; }
public int CPFirmID { get; set; }
public double CreditDfferenceNotional { get; set; }
public string Currency { get; set; }
}
public class Commission
{
public int CommID { get; set; }
public PeriodStart { get; set; }
public ResearchCredit { get; set; }
}
public class CommissionList
{
public List<Commission> Commissions { get { return GetCommissions(); }}
private List<Commission> GetCommissions()
{
// retrieve data code ... ...
}
}
public class TradeBalanceBreakModel
{
public List<TradeBalanceBreak> TradeBalanceBreaks { get; set; }
}
public class CommissionModel
{
public List<CommissionList> CommissionLists { get; set; }
}
What I would like to achieve is to combine/flatten the TradeBalancesBreaks and CommissionLists (from the model classes) into one. The CommID is shared between the two.
Thanks.
Using Join (extension method version) -- after your update
var list1 = GetTradeBalanceBreaks();
var list2 = new CommisionsList().Commissions;
var combined = list1.Join( list2, l1 => l1.ID, l2 => l2.First().ID,
(l1,l2) = > new
{
l1.CommID,
l1.CPFirmID,
l1.CreditDifferenceNotional,
l1.Currency,
PeriodStarts= l2.SelectMany( l => l.PeriodStart ),
ResearchCredits = l2.SelectMany( l => l.ResearchCredit )
})
.ToList();
var combined = from p in PhoneNumbers
join a in Addresses on a.ID equals p.ID
select new {
ID = p.ID,
Name = p.Name,
Phone = p.Phone,
Address = a.Address,
Fax = a.Fax
};