How to use split in linq query? - linq

I am trying to call the following query string but I am getting 'no data' message on the client-side - 'api/data?id=786,899&price_type=cvr'.
public HttpResponseMessage Get([FromUri] Query query)
{
var data = db.database_ICs.AsQueryable();
if (query.id!= null)
{
data = data.Where(c => query.id.Split(',').Contains(c.ID));
}
if (query.price_type != null)
{
data = data.Where(c => c.Cover == query.price_type);
}
if (!data.Any())
{
var message = string.Format("No data was found");
return Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
}
return Request.CreateResponse(HttpStatusCode.OK, data);
}
public class Query
{
public string id{ get; set; }
public string price_type { get; set; }
public Nullable<DateTime> startDate { get; set; }
public Nullable<DateTime> endDate{ get; set; }
}
Any help would be very much appreciated.
Many Thanks.

var data = db.database_ICs.AsQueryable();
if (!string.IsNullOrEmpty(query.id))
{
var ids = query.id.Split(',').ToList();
data = data.Where(c => ids.Contains(c.ID));
}
Assuming c.ID and ids elements are of the same type of course.
Edit: one way of checking if you have the querystring or not

Related

Asp.Net Core / Entity Framework Core - System.Linq.Enumerable+SelectEnumerableIterator`2[MyClass,System.String]

I am trying to return a json array of my 3rd level depth related data, the issue here is that I get the result with the right property name but with a non clear value content, I failed to find a similar case to solve it. From the returned value message it looks like I am returning a queryable instead of the final result and I need to iterate over it, I've tried several ways to achive that but failed to find the right one.
The json result:
[
{
"registeredYear": "System.Linq.Enumerable+SelectEnumerableIterator`2[MyPath.Groups.GroupYear,System.String]"
}
]
The api endpoint
public async Task<ActionResult<IEnumerable<UserGroup>>> GetUserGroupYears(string email, string groupName)
{
var groupYears = await _repo.GetUserGroupYears(email, groupName);
var mappedEntities = _mapper.Map<GroupYearsListDto[]>(groupYears);
return Ok(mappedEntities);
}
The Repository method
public async Task<IEnumerable<UserGroup>> GetUserGroupYears(string email, string groupName)
{
var userGroupYears = _context.UserGroups
.Include(uo => uo.Group.GroupYears)
.ThenInclude( oy => oy.Year)
.Where(uo => uo.Group.Name == groupName && uo.Email == email );
return await userGoupYears.ToArrayAsync();
}
The used classes:
public class UserGroup
{
public string Email { get; set; }
public string UserId { get; set; }
public virtual User User { get; set; }
public string GroupId { get; set; }
public virtual Group Group { get; set; }
}
public class Group
{
public string Name { get; set; }
public virtual ICollection<UserGroup> Users { get; set; }
public virtual ICollection<GroupYear> GroupYears { get; }
}
public class GroupYear {
public string GroupId { get; set; }
public virtual Group Group { get; set; }
public string YearId { get; set; }
public virtual Year Year { get; set; }
public string RegisteredYear { get; set; }
}
The data transfer object and the mapping:
public class GroupYearsListDto
{
public string RegisteredYear { get; set; }
}
public CoreMappingProfiles()
{
CreateMap<UserGroup, GroupYearsListDto>()
.ForMember(
dest => dest.RegisteredYear,
opt => opt.MapFrom(src => src.Group.GroupYears.Select(x => x.RegisteredYear))
);
}
Update: Attaching a debugger shows that the repository method is returning an IQueryable including the correct values and the controller method makes something wrong when mapping. So I think the following line is responsible of that wrong result:
var mappedEntities = _mapper.Map<GroupYearsListDto[]>(GroupYears);
You are getting this JSON result:
[
{
"registeredYear": "System.Linq.Enumerable+SelectEnumerableIterator`2[MyPath.Groups.GroupYear,System.String]"
}
]
Because you are mapping an IEnumerable<string> to a string, as I mentioned in my comment. So essentially you are getting the same as:
CreateMap<UserGroup, GroupYearsListDto>()
.ForMember(
dest => dest.RegisteredYear,
opt => opt.MapFrom(src =>
{
IEnumerable<string> registeredYears = src.Group.GroupYears.Select(x => x.RegisteredYear);
return registeredYears.ToString();
})
);
And registeredYears.ToString() is "System.Linq.Enumerable+SelectEnumerableIterator`2[MyPath.Groups.GroupYear,System.String]".
I imagine you will either:
Only have one - so do something like: src.Group.GroupYears.Select(x => x.RegisteredYear).Single()
Have multiples - so do something like: string.Join(", ", src.Group.GroupYears.Select(x => x.RegisteredYear))
You have many options, but you need to actually return a string to that property or else you will just get the ToString() version of IEnumerable<string>.
UPDATE:
Based on your comments below, you can try this:
Repository:
public IQueryable<GroupYear> GetGroupYears(string email, string groupName)
{
return _context
.UserGroups
.Where(x => x.Group.Name == groupName && x.Email == email)
.SelectMany(x => x.Group.GroupYears);
}
Controller:
public async Task<ActionResult<GroupYearsListDto[]>> GetGroupYears(string email, string groupName)
{
var groupYears = _repo.GetGroupYears(email, groupName);
var projection = _mapper.ProjectTo<GroupYearsListDto>(groupYears)
var mappedEntities = await projection.ToArrayAsync();
return Ok(mappedEntities);
}
Profile:
CreateMap<GroupYears, GroupYearsListDto>();

How insert multiple value in Intermediate table through API

I use to add value from the VUEJS where write code like this.
<multiselect v-model="schoolTypeform.schoolTypeId" :options="SchoolTypes" :multiple="true" :close-on-select="false" :clear-on-select="false" :preserve-search="true" placeholder="Pick School Type" label="name" track-by="name" :preselect-first="true">
and the JS code for this is written like this:
async addSchool() {
this.isbtnLoading = true;
this.isException = false;
await this.axios.post(this.school, this.form).then(response => {
this.addSchoolType(response.data);
})
},
async addSchoolType(id) {
this.isbtnLoading = true;
this.isException = false;
this.schoolTypeform.shoolId = id;
await this.axios.post(this.apiBasedUrl + '/SchoolsSchoolType', this.schoolTypeform).then(response => {
this.isbtnLoading = false;
});
Now my ER structure is given like this:
School:(Table1)
public partial class Schools
{
public Guid ID { get; set; }
public string Name{ get; set; }
// Navigation
public ICollection<SchoolsSchoolType> SchoolsSchoolTypes { get; set; }
}
SchoolType:(Table2)
public class SchoolType
{
public Guid Id { get; set; }
public string Name { get; set; }
//Navigation
public ICollection<SchoolsSchoolType> SchoolsSchoolTypes { get; set; }
}
SchoolsSchoolType (It is Intermediate table): Here the relation between the above is many to many.
public class SchoolsSchoolType
{
public Guid Id { get; set; }
public Guid ShoolId { get; set; }
public Schools Schools { get; set; }
public Guid SchoolTypeId { get; set; }
public SchoolType SchoolType { get; set; }
}
Here is repository method write for single value input, but I want to add here multiple value in the intermediates or junction table.
public async Task<Guid> CreateSchoolsAsync(SchoolsCreateVm schoolsCreateVm)
{
if (_GpsContext != null)
{
var schoolsEntity = new Schools()
{
ID = Guid.NewGuid(),
Name = schoolsCreateVm.Name,
SchoolsSchoolTypes = new List<SchoolsSchoolType>()
};
var schoolType = new SchoolType();
schoolsEntity.SchoolsSchoolTypes = new List<SchoolsSchoolType>
{
new SchoolsSchoolType
{
ShoolId =schoolsEntity.ID,
SchoolTypeId =schoolType.Id
}
};
return schoolsEntity.ID;
}
return Guid.Empty
}
Controller code is written here:
[HttpPost]
public async Task<IActionResult> PostSchool([FromBody]SchoolsCreateVm schoolsCreateVm)
{
var result = await _schoolsRepository.CreateSchoolsAsync(schoolsCreateVm);
if (result != null)
{
return Ok(result);
}
return NotFound();
}
Here is viewmodel used by me:
public class SchoolsCreateVm
{
public string Name { get; set; }
public List<Guid> SchoolTypeId{ get; set; } // List type of for intermediate table
public SchoolsCreateVm()
{
SchoolTypeId = new List<Guid>();
}
How can insert many schooltype for a single school in the intermediates(many to many) relation table through the VUEJS multiple selects.
Finally I am able to find the solution...
public async Task<Guid> CreateSchoolsAsync(SchoolsCreateVm schoolsCreateVm)
{
if (_GpsContext != null)
{
var schoolId = Guid.NewGuid();
var schoolsEntity = new Schools()
{
ID = schoolId, // 1--[1,2,3]
Name = schoolsCreateVm.Name,
};
// Here the code in which we can enter in the multiple table and Intermediate table
var SchoolsSchoolTypeList = new List<SchoolsSchoolType>();
foreach(var item in schoolsCreateVm.SchoolTypeId)
{
SchoolsSchoolTypeList.Add(new SchoolsSchoolType
{
Id = Guid.NewGuid(),
ShoolId = schoolId,
SchoolTypeId = item,
});
}
await _GpsContext.School.AddAsync(schoolsEntity);
_GpsContext.SchoolsSchoolTypes.AddRange(SchoolsSchoolTypeList);//Enter here for intermediate table that is 'SchoolsSchoolTypes'
await _GpsContext.SaveChangesAsync();
return schoolsEntity.ID;
}
return Guid.Empty;
}

Having issue while trying to pass two model to the same view at a time in mvc 3

I'm trying to create my profile type page for my simple blog site. I have two simple model class like this:
public class UserInfoModel
{
public string UserName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
}
public class NewPost
{
public string PostTitle { get; set; }
public string PostStory { get; set; }
}
I have created a joint model class of user & post to pass to view like this:
public class UserPostModel
{
public UserInfoModel User { get; set; }
public NewPost Post { get; set; }
}
The methods I wrote to retrieve the user & post info are like this:
public int GetUserID(string _UserName)
{
using (var context = new TourBlogEntities1())
{
var UserID = from s in context.UserInfoes
where s.UserName == _UserName
select s.UserID;
return UserID.Single();
}
}
public UserInfo GetUserDetails(int _UserID)
{
using (var context = new TourBlogEntities1())
{
var UserDetails = (from s in context.UserInfoes
where s.UserID == _UserID
select s).Single();
return UserDetails;
}
}
public Post GetUserPosts(int _UserID)
{
using (var context = new TourBlogEntities1())
{
var entity = (from s in context.Posts
where s.UserID == _UserID
select s).Single();
return entity;
}
}
And finally I'm calling all my method from my controller action like this:
[Authorize]
public ActionResult MyProfile()
{
var Business = new Business();
var UserID=Business.GetUserID(User.Identity.Name);
var UserEntity=Business.GetUserDetails(UserID);
var PostEntity=Business.GetUserPosts(UserID);
var model = new UserPostModel();
model.User.UserName = UserEntity.UserName; // problem showing here
model.User.Email = UserEntity.Email;
model.Post.PostTitle = PostEntity.PostTitle;
model.Post.PostStory = PostEntity.PostStory;
return View("MyProfile",model);
}
A run time error showing like " object is not referenced to a object type or null object". I worked ok in a very similar way while passing single model. Whats I'm doing wrong here?
Modified your UserPostModel
public class UserPostModel
{
public UserPostModel()
{
User = new UserInfoModel();
Post = new Post();
}
public UserInfoModel User { get; set; }
public NewPost Post { get; set; }
}
NOTE: check each value before set to model it should not be null.

"An entity object cannot be referenced by multiple instances of IEntityChangeTracker in C#"

Need help with this please.
I need to save some data in session to DB on controller action. But i get the "An entity object cannot be referenced by multiple instances of IEntityChangeTracker in C#" error on
answer.Add(answer);
can anybody help me with this?
Questionare questionare = unitOfWork.QuestionareRepository.GetByID(id);
SADEntitiesContext db = new SADEntitiesContext();
foreach (Question question in questionare.Questions)
{
//check if there are data in Session and save it
_question = "question"+question.QuestionID.ToString();
if (Session[_question] != null)
{
var answer = new Answers();
if (TryUpdateModel(answer))
{
questionanswer = (QuestionAnswerData)Session[_question];
int qID = Int16.Parse(questionanswer.QuestionID);
var answertoupdate = answer.GetAnswer(qID, questionanswer.UserID, questionanswer.EmployeID);
//db.Answers.Remove(answertoupdate);
answer.UserName = questionanswer.UserID;
answer.Answer = db.AnswerChoices.Find(Int16.Parse(questionanswer.AnswerID));
answer.AnsweredAt = DateTime.Now;
answer.locked = false;
answer.Question = question;
answer.Questionare = questionare;
if (questionanswer.EmployeID != null)
{
answer.AnswerAboutUser = questionanswer.EmployeID;
}
if (answertoupdate != null)
{
answertoupdate = answer;
ok = (answertoupdate.Save() > 0);
}
else
{
answer.Add(answer);
ok = (answer.Save() > 0);
}
}
}
answers class
public class Answers
{
SADEntitiesContext db = new SADEntitiesContext();
public int AnswersId { get; set; }
//[Display(Name = "DataResposta", ResourceType = typeof(Resources))]
public DateTime AnsweredAt { get; set; }
//[Display(Name = "bloqueado", ResourceType = typeof(Resources))]
public bool locked { get; set; }
// [Display(Name = "UserName", ResourceType = typeof(Resources))]
public string UserName { get; set; }
//[Display(Name = "AnswersAboutUser", ResourceType = typeof(Resources))]
public string AnswerAboutUser { get; set; }
//[Display(Name = "Resposta", ResourceType = typeof(Resources))]
public virtual AnswerChoices Answer { get; set; }
//[Display(Name = "Questionare", ResourceType = typeof(Resources))]
public virtual Questionare Questionare { get; set; }
//[Display(Name = "QuestionID", ResourceType = typeof(Resources))]
public virtual Question Question { get; set; }
//
// Persistence
public int Save()
{
return db.SaveChanges();
}
public Answers GetAnswer(int questionID, string employeID, string userID)
{
return db.Answers
.Where(e => e.UserName == userID
&& e.Question.QuestionID == questionID
&& e.AnswerAboutUser == employeID)
.FirstOrDefault();
}
public Answers GetAnswer(int id)
{
return db.Answers.SingleOrDefault(d => d.AnswersId == id);
}
//
// Insert/Delete Methods
public void Add(Answers _answer)
{
db.Answers.Add(_answer);
db.SaveChanges();
}
}
}
Your problem is you're calling an answer from one context:
answer.Answer = db.AnswerChoices.Find(Int16.Parse(questionanswer.AnswerID));
and then attempting to save it using a different in your Answer class:
SADEntitiesContext db = new SADEntitiesContext();
The quickest solution to your problem would be to be able to set the context in your Answer class, so that your not jumping contexts, or you could Detach the answer after pulling it from the db the first time, and then reattach it in the save.
However, I think you have a more fundamental problem. Are you sure it's a good idea to have a class be able to create it's own context, and save itself? You'll have problems like this all over the place.

Joining Linq Expressions

I'm working with the new EF4 CTP4 although I don't think this has much to do with that. I am trying to set up a system where I can add auditable fields for our database automatically. What I'm trying to do is combine the following two expressions
a => new
{
a.CreatedBy,
a.CreatedTime,
a.UpdatedBy,
a.UpdatedTime
}
and
a => new
{
a.Id,
a.Name,
}
so the result is equivalant to
a => new
{
a.Id,
a.Name,
a.CreatedBy,
a.CreatedTime,
a.UpdatedBy,
a.UpdatedTime
}
the result I need to be an Expression<Func<T, object>>. I've been poking around and tried several things with Expression.Invoke and Expression.And(andalso) and haven't found anything that is working for me.
I'm not quite sure if this is possible but any help would be appreciated.
I don't think you can simply 'merge' two expressions. But you can use alternate API to create mappings with EntityMap.
public static class MapBuilder
{
public static Expression<Func<T, object>> GetMap<T>(Expression<Func<T, object>> func) where T: IAuditable
{
var body = func.Body as NewExpression;
var param = Expression.Parameter(typeof(T), "o");
var propertyAccessExprs = new List<Expression>();
foreach (MemberInfo member in body.Members)
{
propertyAccessExprs.Add(Expression.Property(param, member.Name));
}
var props = typeof(IAuditable).GetProperties();
foreach (PropertyInfo prop in props)
{
propertyAccessExprs.Add(Expression.Property(param, prop.Name));
}
var columnMappins = new List<Expression>();
foreach (var access in propertyAccessExprs)
{
columnMappins.Add(Expression.Call(typeof(EntityMap).GetMethod("Column", new Type[] {typeof(Object)}), Expression.Convert(access, typeof(Object))));
}
var RowExpr = Expression.Call(typeof(EntityMap).GetMethod("Row"), Expression.NewArrayInit(typeof(EntityMapColumn), columnMappins));
var result = Expression.Lambda<Func<T, object>>(RowExpr, param);
return result;
}
}
The usage is
var builder = new ModelBuilder();
builder.Entity<SimpleAuditableObject>()
.HasKey(o => o.Id)
.MapSingleType(MapBuilder.GetMap<SimpleAuditableObject>(o => new { o.Id, o.Name }));
Where
public interface IAuditable
{
int CreatedBy { get; set; }
DateTime CreatedTime { get; set; }
int UpdatedBy { get; set; }
DateTime UpdatedTime { get; set; }
}
public class SimpleAuditableObject : IAuditable
{
public int Id { get; set; }
public string Name { get; set; }
public int CreatedBy { get; set; }
public DateTime CreatedTime { get; set; }
public int UpdatedBy { get; set; }
public DateTime UpdatedTime { get; set; }
}
HTH.

Resources