LINQ ExecuteQuery - c#

I want to use ExecuteQuery() to get IEnumerable of type Entities.UserLevel. Following code works well.
using (CDataContext context = data.GetDataContext())
{
string q = "SELECT *FROM UserLevel";
IEnumerable<Entities.UserLevel> res = context.ExecuteQuery<Entities.UserLevel>(q);
}
public class UserLevel
{
public int userID { get; set; }
public int levID { get; set; }
}
But the problem is that I must use property names in UserLevel class same as in database, otherwise I do not get values. I wonder is there any way to get values irrespective of class/property name? For example, I want to use following UserLevel class instead of above:
public class UserLevel
{
public int UserIdentity { get; set; }
public int LevelIdentity { get; set; }
}

Sure just write.
var q = "SELECT userID as UserIdentity, levID as LevelIdentity FROM UserLevel";
var res = context.ExecuteQuery<UserLevelDTO>(q);
But why not use Linq instead? You could write:
var res = from u in context.UserLevel
select new UserLevelDTO()
{
UserIdentity = u.userID,
LevelIdentity = u.levID
};
You would need to create your own DTO class.
public class UserLevelDTO
{
public int UserIdentity { get; set; }
public int LevelIdentity { get; set; }
}

Related

How do I send a Object Linq sorted List as a parameter

I am trying to make my code more compromised, and use overall less, however currently I'm running into the problem of not being able to send a list of Objects sorted by linq as a parameter.
the problem is in this part of the code:
List<Afspraken> dataAfspraken = new List<Afspraken>();
public Form1()
{
InitializeComponent();
fillListsForLinq();
loadReceptionData();
}
private void fillListsForLinq()
{
dataAfspraken = data.getAfsprakenData();
//here it fills the list with Afspraken objects
}
private void loadReceptionData()
{
private void loadReceptionGrid
var receptionToFinnish =
(from AFspraken in dataAfspraken
where Afspraken.factuur_betaald == true && Afspraken.volledig_afgerond == false
join Users in dataUsers on Afspraken.gekoppelde_klant equals Users.id
select new
{
Id = Afspraken.id,
Klant = Users.gebruikersnaam,
Betaald = Afspraken.factuur_betaald,
Afgerond = Afspraken.volledig_afgerond
}).ToList();
changeDataviewReception(receptionToFinnish);
}
private void changeDataviewReception(List<Object> listData)
{
dgvReceptionData.DataSource = listData
}
the Afspraken class looks like this
public class Afspraken
{
public int id { get; set; }
public bool bevestigd { get; set; }
public DateTime datum { get; set; }
public int gekoppelde_klant { get; set; }
public int gekoppelde_monteur { get; set; }
public string benodigde_hadelingen { get; set; }
public decimal totaalprijs { get; set; }
public bool klaar { get; set; }
public bool factuur_betaald { get; set; }
public bool volledig_afgerond { get; set; }
public string opmerkingen { get; set; }
}
How do I get receptionToFinnish as a parameter into changeDataviewReception?
receptionToFinnish will be a list full of objects of an anonymous type. But your method requires a List<object>. This is now allowed since a list is not a variant type.
Say for example that you have a list of bananas and want to give it to someone that wants a list of fruits. This will not work since that other person might try to add an orange to the list of bananas.
To fix this, cast the values to object explicitly, for example:
select new
{
Id = Afspraken.id,
Klant = Users.gebruikersnaam,
Betaald = Afspraken.factuur_betaald,
Afgerond = Afspraken.volledig_afgerond
} as object

query IEnumerable array and select all x.profilenames

ok so this is maybe very simple but I just can not see where I am going wrong so any help is grateful
I have a model of this:
public IEnumerable<SelectedProfiels> profiles { get; set; }
public class SelectedProfiels
{
public int Identifer { get; set; }
public string ProfileName { get; set; }
}
and then I am trying to read from this
i am then building an array called selectedProfiles,
I then have this code
var pro = from s in selectedProfiles select s;
What im wanting to do is find all the ProfileName's and assigned them there on ViewBag.[i] or just there own string variable
I have a model collection like this
var userd = new User()
{
ID = i.FirstOrDefault(),
Type = t.FirstOrDefault(),
AuthorityLevel = a.FirstOrDefault(),
Language = l.FirstOrDefault(),
Profiles = pro,
};
public IEnumerable<SelectedProfiels> profiles { get; set; }
public class SelectedProfiels
{
public int Identifer { get; set; }
public string ProfileName { get; set; }
}
I then pass userd to a new page:
return RedirectToAction("test", "Account", userd);
public ActionResult test (Userm)
{
ViewBag.d = m.profiles;
return View();
}
any help please
So, given your linq query:
var pro = from s in
selectedProfiles
select s;
You can use Linq to generate an IEnumerable from pro, like:
var selectedProfiles = pro.Select(p => p.ProfileName).ToList();
Then, you can use selectedProfiles to populate the array you desire:
string[] newStrings = selectedProfiles.ToArray();
Instead of
select s
Just use
select s.ProfileName

Find(System.Object[]) cannot be called with instance of type .ObjectQuery [duplicate]

I want to Find Username by userId
this code snippet working
Discussion_CreateBy = db.AspNetUsers.Find(discussion.CreatedBy).UserName,
and this once not working in following controller class
Comment_CreateBy = db.AspNetUsers.Find(c.CreatedBy).UserName,
this is my model classes
public class DiscussionVM
{
public int Disussion_ID { get; set; }
public string Discussion_Title { get; set; }
public string Discussion_Description { get; set; }
public Nullable<System.DateTime> Discussion_CreateDate { get; set; }
public string Discussion_CreateBy { get; set; }
public string Comment_User { get; set; }
public IEnumerable<CommentVM> Comments { get; set; }
}
public class CommentVM
{
public int Comment_ID { get; set; }
public Nullable<System.DateTime> Comment_CreateDate { get; set; }
public string Comment_CreateBy { get; set; }
public string Comment_Description { get; set; }
}
this is whole controller class
public ActionResult Discussion_Preview()
{
int Discussion_ID = 1;
var discussion = db.AB_Discussion.Where(d => d.Discussion_ID == Discussion_ID).FirstOrDefault();
var comments = db.AB_DiscussionComments.Where(c => c.Discussion_ID == Discussion_ID);
DiscussionVM model = new DiscussionVM()
{
Disussion_ID = discussion.Discussion_ID,
Discussion_Title = discussion.Discussion_Name,
Discussion_Description = discussion.Discussion_Name,
Discussion_CreateBy = db.AspNetUsers.Find(discussion.CreatedBy).UserName,
Discussion_CreateDate = discussion.CreatedDate,
Comments = comments.Select(c => new CommentVM()
{
Comment_ID = c.Comment_ID,
Comment_Description = c.Comment_Discription,
Comment_CreateBy = db.AspNetUsers.Find(c.CreatedBy).UserName,
Comment_CreateDate = c.CreatedDate
})
};
return View(model);
}
Getting following error
Method 'Project.Models.AspNetUser Find(System.Object[])' declared on type 'System.Data.Entity.DbSet1[Project.Models.AspNetUser]' cannot be called with instance of type 'System.Data.Entity.Core.Objects.ObjectQuery1[Project.Models.AspNetUser]'
Discussion_CreateBy = db.AspNetUsers.Find(discussion.CreatedBy).UserName
Works because discussion is an in-memory object because you are executing a query by calling FirstOrDefault on it:
var discussion = db.AB_Discussion.Where(d => d.Discussion_ID == Discussion_ID).FirstOrDefault();
On the other hand in the following statement:
db.AspNetUsers.Find(c.CreatedBy).UserName
c is not queried yet because
db.AB_DiscussionComments.Where(c => c.Discussion_ID == Discussion_ID)
returns an IQueriable and not the actual collection of comments
The easiest way to fix it is to bring all your comments into memory (since you are anyway need them all) :
var comments = db.AB_DiscussionComments.Where(c => c.Discussion_ID == Discussion_ID).ToList();

EF adding duplicate records into lookup/reference table

I have 3 tables,
1. AttributeTypes (Columns: AttributeId (PK), AttributeName, ..)
2. Location (Columns: locationId (PK), LocationName, ...)
3. LocationAttributeType (Columns: locationId (FK), AttributeId (FK))
Whenever I am trying to insert new location record along with its attribute type from GUI, it should create new record for Table- Location and LocationAttributeType. But EF trying to add new record in Table- AttributeTypes as well, which is just used as reference table and should not add new/duplicate records in it. How can I prevent that?
here is my code,
The model which GUI sends is,
public class LocationDataModel
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Code { get; set; }
[DataMember]
public List<AttributeTypeDataModel> AssignedAttributes = new List<AttributeTypeDataModel>();
}
public class AttributeTypeDataModel
{
protected AttributeTypeDataModel() {}
public AttributeTypeDataModel(int id) { this.Id = id; }
public AttributeTypeDataModel(int id, string name)
: this(id)
{
this.Name = name;
}
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public virtual ICollection<LocationDataModel> Locations { get; set; }
}
The Entities created by EF are,
public partial class Location
{
public Location()
{
this.AttributeTypes = new List<AttributeType>();
}
public Location(int campusId, string code)
: this()
{
CampusId = campusId; Code = code;
}
public int Id { get; set; }
public int CampusId { get; set; }
public string Code { get; set; }
public virtual ICollection<AttributeType> AttributeTypes { get; set; }
}
public partial class AttributeType
{
public AttributeType()
{
this.Locations = new List<Location>();
}
public int AttributeTypeId { get; set; }
public string AttributeTypeName { get; set; }
public virtual ICollection<Location> Locations { get; set; }
}
I have below code to Add these new location to database,
private IEnumerable<TEntity> AddEntities<TModel, TEntity, TIdentityType>
(IEnumerable<TModel> models, Func<TModel, TIdentityType> primaryKey,
IGenericRepository<TEntity, TIdentityType> repository)
{
var results = new List<TEntity>();
foreach (var model in models)
{
var merged = _mapper.Map<TModel, TEntity>(model);
var entity = repository.Upsert(merged);
results.Add(entity);
}
repository.Save();
return results.AsEnumerable();
}
I am using following generic repository to do entity related operations
public TEntity Upsert(TEntity entity)
{
if (Equals(PrimaryKey.Invoke(entity), default(TId)))
{
// New entity
return Context.Set<TEntity>().Add(entity);
}
else
{
// Existing entity
Context.Entry(entity).State = EntityState.Modified;
return entity;
}
}
public void Save()
{
Context.SaveChanges();
}
Whats wrong I am doing here?
The DbSet<T>.Add() method attaches an entire object graph as added. You need to indicate to EF that the 'reference' entity is actually already present. There are two easy ways to do this:
Don't set the navigation property to an object. Instead, just set the corresponding foreign key property to the right value.
You need to ensure that you don't load multiple instances of the same entity into your object context. After creating the context, load the full list of AttributeType entities into the context and create a Dictionary<> to store them. When you want to add an attribute to a Location retrieve the appropriate attribute from the dictionary. Before calling SaveChanges() iterate through the dictionary and mark each AttributeType as unchanged. Something like this:
using (MyContext c = new MyContext())
{
c.AttributeTypes.Add(new AttributeType { AttributeTypeName = "Fish", AttributeTypeId = 1 });
c.AttributeTypes.Add(new AttributeType { AttributeTypeName = "Face", AttributeTypeId = 2 });
c.SaveChanges();
}
using (MyContext c = new MyContext())
{
Dictionary<int, AttributeType> dictionary = new Dictionary<int, AttributeType>();
foreach (var t in c.AttributeTypes)
{
dictionary[t.AttributeTypeId] = t;
}
Location l1 = new Location(1, "Location1") { AttributeTypes = { dictionary[1], dictionary[2] } };
Location l2 = new Location(2, "Location2") { AttributeTypes = { dictionary[1] } };
// Because the LocationType is already attached to the context, it doesn't get re-added.
c.Locations.Add(l1);
c.Locations.Add(l2);
c.SaveChanges();
}
In this specific case you are using a many-to-many relationship, with EF automatically handling the intermediate table. This means that you don't actually have the FK properties exposed in the model, and my first suggestion above won't work.
Therefore, you either need to use the second suggestion, which still ought to work, or you need to forgo the automatic handling of the intermediate table and instead create an entity for it. This would allow you to apply the first suggestion. You would have the following model:
public partial class Location
{
public Location()
{
this.AttributeTypes = new List<LocationAttribute>();
}
public Location(int campusId, string code)
: this()
{
CampusId = campusId; Code = code;
}
public int Id { get; set; }
public int CampusId { get; set; }
public string Code { get; set; }
public virtual ICollection<LocationAttribute> AttributeTypes { get; set; }
}
public partial class LocationAttribute
{
[ForeignKey("LocationId")]
public Location Location { get; set; }
public int LocationId { get; set; }
public int AttributeTypeId { get; set; }
}
public partial class AttributeType
{
public int AttributeTypeId { get; set; }
public string AttributeTypeName { get; set; }
}
With this approach you do lose functionality since you can't navigate from a Location to an AttributeType without making an intermediate lookup. If you really want to do that, you need to control the entity state explicitly instead. (Doing that is not so straightforward when you want to use a generic repository, which is why I've focused on this approach instead.)
Thank you all for your suggestions.
I have to get rid of my generic repository here to save my context changes and do it manually as below,
private IEnumerable<int> AddLocationEntities(IEnumerable<LocationDataModel> locations)
{
var results = new List<int>();
foreach (LocationDataModel l in locations)
{
var entity = _mapper.Map<LocationDataModel, Location>(l);//you can map manually also
var AttributeCode = l.AssignedAttributes.FirstOrDefault().AttributeTypeId;
using (MyContext c = new MyContext())
{
var attr = c.AttributeTypes.Where(a => a.Id == AttributeTypeId ).ToList();
entity.AttributeTypes = attr;
c.Locations.Add(entity);
c.SaveChanges();
var locid = entity.Id;
results.Add(locid);
}
}
return results;
}
In the else statement of yourUpsert you should add
context.TEntity.Attach(entity);

How to use a dictionary property in C# using LINQ

While I userstand how get; & set; with simple types such as strings now can more properties like Dictionary be get or set or can they?
I have a small dos programe trying to do this. snippet below.
# User.cs
namespace LDIFMod
{
public class User
{
public string UserHash { get; set; }
public string UserID { get; set; }
public Dictionary<string, string> UserDict { get; set; } <- how to do this???
}
}
and in my Program.cs
var query = from line in File.ReadAllLines(args[0])
let UserRecord = line.Split(',')
select new User()
{
UserHash = UserRecord[2].Trim() +UserRecord[3].Trim(),
UserID = UserRecord[4].Trim(),
UserDict.???? // userDict should contain key = UserRecord[5] & value = UserRecord[9]
}
You will need to first initialize the dictionary in the constructor of the user class. Use the private set to prevent people from re-initializing the dictionary.
# User.cs
namespace LDIFMod
{
public class User
{
User()
{
UserDict = new Dictionary<string, string>()
}
public string UserHash { get; set; }
public string UserID { get; set; }
public Dictionary<string, string> UserDict { get; private set; }
}
}
Your calling code becomes
var query = from line in File.ReadAllLines(args[0])
let UserRecord = line.Split(',')
select new User()
{
UserHash = UserRecord[2].Trim() +UserRecord[3].Trim(),
UserID = UserRecord[4].Trim(),
UserDict.Add(UserRecord[5],UserRecord[9]);
}
This returns one dictionary per query row. if you want all of the rows to share a dictionary you will need to make it static or not store it inside User. If you do this be aware that linq is delayed execution so the dictionary will not be fully populated until after you fully enumerate the query.
I thought I would give a example of how to do it with all of them in a single dictionary.
# User.cs
namespace LDIFMod
{
public class User
{
public string UserHash { get; set; }
public string UserID { get; set; }
public readonly string[] SourceData {get; private set;}
}
}
and here is the query
var query = from line in File.ReadAllLines(args[0])
let UserRecord = line.Split(',')
select new User()
{
UserHash = UserRecord[2].Trim() + UserRecord[3].Trim(),
UserID = UserRecord[4].Trim(),
SourceData = UserRecord;
}
var UserLookp = query.ToDictionary((user) => user.SourceData[5], (user) => user.SourceData[9]);
This is purely from memory without a ide to check for bugs so there could be some errors.
You can use the collection initializer to create the dictionary:
{
UserHash = UserRecord[2].Trim() +UserRecord[3].Trim(),
UserID = UserRecord[4].Trim(),
UserDict = new Dictionary<string, string> { { UserRecord[5], UserRecord[9] } }
}
Also, see here: http://msdn.microsoft.com/en-us/library/bb531208.aspx

Categories

Resources