I have very strange issue with AutoMapper
In my windows service, When I create mapping from IDataReader to List object, it works for very first time only when i run the service.
As soon as I stop the service and run it again, AutoMapper cannot able to Map. Below is my code:
Property Class
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string Number { get; set; }
}
Actual Implementation
var employeeData = DataHelper.ExecuteReader("Select Id, Name, Number from dbo.Employee");
var employees = new List<Employee>();
employees = employeeData.MapToList<List<Employee>>();
Generic Extension Method
public static T MapToList<T>(this DataTable reader) where T : class
{
Mapper.CreateMap<IDataReader, T>();
// Mapper.AssertConfigurationIsValid();
return Mapper.Map<IDataReader, T>(reader.CreateDataReader());
}
Apart from this, I have noticed that when I clean solution and run service again it starts working.
I am not able to Identify why it behaves like this.
Given your table's fields have the same name as Employee's properties, you should be able to do like this (without any explicit mapping config):
var employeeData = DataHelper.ExecuteReader("Select Id, Name, Number from dbo.Employee");
var employees = AutoMapper.Mapper.DynamicMap<IDataReader, List<Employee>>(employeeData.CreateDataReader());
Related
I've tried this code shown below in another project and it works, so problem is surely not in a method responsible for getting data from database by ID. Unfortunately, I wasn't able figure out what causes the problem.
Simplest test case: I initialize MongoDB class with methods to work with database. Then I load every record stored in database using method LoadRecords() to collection.
// some code
MongoDB db = new MongoDB("People");
List<Person> collection = db.LoadRecords<Person>("Person");
//some code
public List<T> LoadRecords<T>(string table)
{
var collection = db.GetCollection<T>(table);
return collection.Find(new BsonDocument()).ToList();
}
That works fine, it gives me collection of every document in table. Now I try to find only one element with, for example, ID of first element from that collection using method LoadRecordById().
// some code
Person oneRecord = db.LoadRecordById<Person>("Person", people[0].Id);
// some code
public T LoadRecordById<T>(string table, Guid id)
{
var collection = db.GetCollection<T>(table);
var filter = Builders<T>.Filter.Eq("ID", id);
return collection.Find(filter).First();
}
My Person class is also very simple, only includes a few properties and ID:
[BsonIgnoreExtraElements]
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
[BsonId]
public Guid Id { get; set; }
}
It really makes no sense to me, first it gives me every record stored in database (its FirstName, LastName, ID) and then when I want to search one record with the exactly same ID it gave me before, it crashes.
Result is an unhandled exception of type 'System.InvalidOperationException' occurred in System.Core.dll
Additional information: Sequence contains no elements
I have stored procedure attached to a DB which should return results from just a simple search. The query is added to my entity and calls a regular method. The problem I face is storing the results from this procedure to a particular DTO as a list.
Is there any way to effectively store the results from this stored procedure as a list to the DTO?
Below is what I have so far
Controller:
[Produces("application/json")]
[RoutePrefix("api/jobs")]
public class OutputController : ApiController
{
private TestCoastalToolsEntities _output;
public OutputController()
{
_output = new TestCoastalToolsEntities();
_output.Configuration.ProxyCreationEnabled = false;
}
/**Search**/
// POST: api/postsearch
[System.Web.Http.HttpPost, System.Web.Http.Route("postsearch")]
public async Task<IHttpActionResult> PostSearch(SearchInputDTO srequest)
{
OutputDTO<SearchInputDTO> output = new OutputDTO<SearchInputDTO>();
SearchInputDTO SearchInput = null;
var searchString = srequest.SearchValue.ToString();
SearchInput.Results = _output.searchLog2(searchString);
if (_oput != null)
{
output.Success = true;
output.Results = _SearchInput.Results;
var json = new JavaScriptSerializer().Serialize(output);
return Ok(json);
}
return Ok(_ot);
}
}
}
-------------------------------------
Search DTO:
namespace toolPortal.API.Data.DTO
{
public class SearchInputDTO
{
public List<object> Results { get; set; }
public SearchInputDTO(output output) {
this.ID = output.ID;
this.Name = output.Name;
this.Job = output.Job;
this.Start = output.Start;
this.End = output.End;
this.Logs = output.Logs;
}
}
}
The expected result is that the stored procedure runs and stores the list of results to SearchInputResults. From there, those results should be stored in another DTO to be passed off on the return.
With EF you will want to leverage Select() to map the entities to your DTO, though you will need to consider the entire structure of the DTO. For instance, what is the "Logs" data structure going to comprise of? Is it a single string value, a list of strings, or a list of log records?
Using Select() you need to leverage property setters, not a constructor accepting an entity.
So a pattern like this:
public class Entity
{
public string Field { get; set; }
}
public class Dto
{
public string Field { get; set; }
}
var dtos = context.Entities
.Where(x => x.IsActive)
.Select(x => new Dto
{
Field = x.Field
})
.ToList();
Looking at your example with the constructor:
public class Dto
{
public string Field { get; private set; }
public Dto(Entity entity)
{
Field = entity.Field;
}
}
var dtos = context.Entities
.Where(x => x.IsActive)
.Select(x => new Dto(x))
.ToList();
This doesn't work with EF & Select. EF can map to an object, but only via properties and a parameterless constructor. There is a hack around this to be aware of, but avoid if you do see it:
var dtos = context.Entities
.Where(x => x.IsActive)
.ToList()
.Select(x => new Dto(x))
.ToList();
With the extra ToList() before the select, the call will work because EF will execute the query and return the list of entities, then the Select() will be performed as a Linq2Object query. The reason you should avoid this is because EF will select all properties from the entity, where we should only pull back the properties we care about. It's also easy to fall into a lazy-load performance trap if your Dto constructor population starts iterating over related entities. Using Select to load just the fields you need from an entity and any related entities allows EF to build an efficient query for just the data needed without any lazy load traps.
Using AutoMapper you can simplify this by setting up the mapping from entity to DTO then leveraging ProjectTo<Dto>().
So, if you want a DTO to represent the results (such as a success flag, error message) with a collection of the results if successful:
[Serializable]
// Our results container.
public class SearchResultsDTO
{
public bool IsSuccessful { get; private set; } = false;
public string ErrorMessage { get; private set; }
public ICollection<SearchResultDTO> Results { get; private set; } = new List<SearchResultDTO>();
private SearchResultsDTO() {}
public static SearchResultsDTO Success(ICollection<SearchResultDTO> results)
{
var results = new SearchResultsDTO
{
IsSuccessful = true,
Results = results
};
return results;
}
public static SearchResultsDTO Failure(string errorMessage)
{
var results = new SearchResultsDTO
{
ErrorMessage = errorMessage
};
return results;
}
}
[Serializable]
public class SearchResultDTO
{
public int ID {get; set;}
public string Name {get; set;}
public string Job {get; set;}
public DateTime Start {get; set;}
public DateTime End {get; set;}
public ICollection<string> Logs {get; set;} = new List<string>();
}
then to populate these from a DbContext: (Inside a Repository or wherever reads the data)
using (var context = new SearchContext())
{
var results = context.Logs
.Where(x => x.Name.Contains(sRequest))
.Select(x => new SearchResultDTO
{
ID = x.ID,
Name = x.Name,
Job = x.Job,
Start = x.Start,
End = x.End,
Logs = x.LogLines.Select(y => y.Line).ToList(),
}).ToList();
var resultDto = SearchResultsDTO.Success(results);
return resultsDto;
}
This assumes that the log entry has a Job, name, start, end date/times, and then a list of "lines" or entries to display as "Logs". (Where the Log table has a related LogLine table for example with the one or more lines) This demonstrates how to leverage Select to map not only the log record into a DTO, but also to map related records into something like a collection of strings, or a collection of other DTOs can be done as well.
Once it selects the DTO, I have it fill a container DTO using static factory methods to populate either a successful read, or a failed read. (which can be set in an exception handler for example.) Alternatively you can just new up a container class and populate properties, use a constructor /w parameters, or just return the list of DTOs. The SearchResultsDTO container is not referenced within the EF query.
I am making an app using the ASP.Net Boilerplate framework and in my Domain layer I have a simple "Boss" entity. Creating and retrieving these entities from the database works fine but I can't get the "Update" to work. When map my "UpdateBossDto" to a Boss object and try to update it I get this error:
$exception {System.InvalidOperationException: The instance of entity
type 'Boss' cannot be tracked because another instance with the same
key value for {'Id'} is already being tracked. When attaching existing
entities, ensure that only one entity instance with a given key value
is attached. Consider using
'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the
conflicting key values.
This error gets thrown in the BossManager class (I have removed the other methods for readability.
public class BossManager : DomainService, IBossManager
{
private readonly IRepository<Boss> _repositoryBoss;
public BossManager(IRepository<Boss> repositoryBoss)
{
_repositoryBoss = repositoryBoss;
}
public void Update(Boss entity)
{
_repositoryBoss.UpdateAsync(entity);
}
}
Here is my Update method in the BossAppService (i know getting the Id this way probably isn't great but right now I'm just desperate):
public void Update(UpdateBossDto updatedBoss)
{
var boss = new Boss();
updatedBoss.Id = _bossManager.GetBossIdByName(updatedBoss.Name);
boss = ObjectMapper.Map<Boss>(updatedBoss);
_bossManager.Update(boss);
}
And my UpdateDto class which holds the same attributes as the Boss class itself:
public class UpdateBossDto
{
public int Id { get; set; }
public string Name { get; set; }
public int Hp { get; set; }
public int CombatLvl { get; set; }
public int MaxHit { get; set; }
public string AttackStyle { get; set; }
public string Weakness { get; set; }
public string ImageUrl { get; set; }
}
How can I update the Boss object either with or without the Id? Any help would be greatly appreciated!
There's a number of issues here. First, the id should be coming from the request URL, since it uniquely identifies the resource that's being modified. This also saves you from having to do silly things like GetBossIdByName. Not only does that require an unnecessary query, but it's prone to error. The id is your key for a reason: it's unique. Names are not. You could have multiple bosses with the same name. Additionally, your name columns are likely not indexed, which means such a query is vastly more inefficient. Then, with your id, you should be querying the corresponding Boss out of your database, and mapping onto this instance, not creating a new instance. Finally, save that same instance back to the database. Then, you will have no issues.
I have a code-first EF database where objects have "statuses" to track history. They're implemented something like this:
public class Example
{
public Example()
{
this.Statuses = new HashSet<Status>();
}
public Guid Id { get; set; }
public virtual ICollection<Status> Statuses { get; set; }
}
public class Status
{
public Guid Id { get; set; }
public DateTimeOffset SetOn { get; set; }
public string SetBy { get; set; }
}
We have a few instances in code where we need to get either the oldest or newest status. Currently we've been using chained linq expressions like the following:
var setBy = example.Statuses.OrderByDescending(s => s.SetOn).FirstOrDefault().SetBy;
I think it would be more readable if we could do some of that with extensions, since getting the newest or oldest status is just a difference of whether it's sorted by ascending or descending.
A simple extension method like this works with linq-to-objects, if we've already gotten results from the database:
public static Status Newest(this IQueryable<Status> items)
{
return items.OrderByDescending(s => s.SetOn).FirstOrDefault();
}
However, this doesn't work if I'm running it on an IQueryable representing our database, since EF is unable to translate it to a store expression. For instance, if "repository" below is an IQueryable<Example> representing Examples in a SQL backend, the following will fail:
var date = DateTimeOffset.Parse("4/1/2018");
var query = repository.Where(ex => ex.Statuses.Newest().SetOn > date).FirstOrDefault();
Is there a way I can refactor this into an extension method or expression that can be translated to a store expression?
This can be done with LINQKit by defining an expression that returns a Status from an Example, and wrapping the IQueryable with LINQKit's Expandable. Using the above classes, I could do something like
private Expression<Func<Example, Status>> Newest =
e => e.Statuses.OrderByDescending(s => s.SetOn).FirstOrDefault();
And invoke it like
var results = from example in repository.AsExpandable()
select new
{
Example = example,
LatestStatus = Newest.Invoke(example)
};
Can anyone provide an easier more automatic way of doing this?
I have the following save method for a FilterComboTemplate model. The data has been converted from json to a c# model entity by the webapi.
So I don't create duplicate entries in the DeviceProperty table I have to go through each filter in turn and retrieve the assigned DeviceFilterProperty from the context and override the object in the filter. See the code below.
I have all the object Id's if they already exist so it seems like this should be handled automatically but perhaps that's just wishful thinking.
public void Save(FilterComboTemplate comboTemplate)
{
// Set the Device Properties so we don't create dupes
foreach (var filter in comboTemplate.Filters)
{
filter.DeviceProperty = context.DeviceFilterProperties.Find(filter.DeviceFilterProperty.DeviceFilterPropertyId);
}
context.FilterComboTemplates.Add(comboTemplate);
context.SaveChanges();
}
From here I'm going to have to check whether any of the filters exist too and then manually update them if they are different to what's in the database so as not to keep creating a whole new set after an edit of a FilterComboTemplate.
I'm finding myself writing a lot of this type of code. I've included the other model classes below for a bit of context.
public class FilterComboTemplate
{
public FilterComboTemplate()
{
Filters = new Collection<Filter>();
}
[Key]
public int FilterComboTemplateId { get; set; }
[Required]
public string Name { get; set; }
[Required]
public ICollection<Filter> Filters { get; set; }
}
public class Filter
{
[Key]
public int FilterId { get; set; }
[Required]
public DeviceFilterProperty DeviceFilterProperty { get; set; }
[Required]
public bool Exclude { get; set; }
[Required]
public string Data1 { get; set; }
}
public class DeviceFilterProperty
{
[Key]
public int DeviceFilterPropertyId { get; set; }
[Required]
public string Name { get; set; }
}
Judging from some similar questions on SO, it does not seem something EF does automatically...
It's probably not a massive cut on code but you could do something like this, an extension method on DbContext (or on your particular dataContext):
public static bool Exists<TEntity>(this MyDataContext context, int id)
{
// your code here, something similar to
return context.Set<TEntity>().Any(x => x.Id == id);
// or with reflection:
return context.Set<TEntity>().Any(x => {
var props = typeof(TEntity).GetProperties();
var myProp = props.First(y => y.GetCustomAttributes(typeof(Key), true).length > 0)
var objectId = myProp.GetValue(x)
return objectId == id;
});
}
This will check if an object with that key exists in the DbContext. Naturally a similar method can be created to actually return that entity as well.
There are two "returns" in the code, just use the one you prefer. The former will force you to have all entities inherit from an "Entity" object with an Id Property (which is not necessarily a bad thing, but I can see the pain in this... you will also need to force the TEntity param: where TEntity : Entity or similar).
Take the "reflection" solution with a pinch of salt, first of all the performance may be a problem, second of all I don't have VS running up now, so I don't even know if it compiles ok, let alone work!
Let me know if that works :)
It seems that you have some common operations for parameters after it's bound from request.
You may consider to write custom parameter bindings to reuse the code. HongMei's blog is a good start point: http://blogs.msdn.com/b/hongmeig1/archive/2012/09/28/how-to-customize-parameter-binding.aspx
You may use the code in Scenario 2 to get the formatter binding to deserialize the model from body and perform the operations your want after that.
See the final step in the blog to specify the parameter type you want customize.