Edit value on mapping with AutoMapper - automapper

I'm trying to refactor my project and use automapper to map view model to entity model. Here is my my current code. I have used Guid.NewGuid(), GetValueOrDefault() and DateTime.Now. How can I edit those value on mapping?
var product = new Product
{
Id = Guid.NewGuid(),
Name = model.Name,
Price = model.Price.GetValueOrDefault(),
ShortDescription = model.ShortDescription,
FullDescription = model.FullDescription,
SEOUrl = model.SEOUrl,
MetaTitle = model.MetaTitle,
MetaKeywords = model.MetaKeywords,
MetaDescription = model.MetaDescription,
Published = model.Published,
DateAdded = DateTime.Now,
DateModified = DateTime.Now
};
then here is my map code
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<Product, ProductCreateUpdateModel>().ReverseMap();
});

Tell me if I understood you right. You want to create AutoMapper configuration, but some of the properties you want to map manually? In this case, you can do following:
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<Product, ProductCreateUpdateModel>()
.ReverseMap()
.ForMember(product => product.Price, expression => expression.MapFrom(model => model.Price.GetValueOrDefault()))
.ForMember(product => product.DateAdded, expression => expression.UseValue(DateTime.Now))
.ForMember(product => product.DateModified, expression => expression.UseValue(DateTime.Now));
});
If not, please, specify your question.

Related

Binding data source in kendo grid on mvc

First of all this is my first work using kendo ui. In work i have some data from database, i would like to replace my mvc webgrid into impressive kendo grid. I have created a list from database and iam trying to bind into kento grid. After setting data source. Still the grid remains empty.
public ActionResult Index()
{
SqlConnection sqcon = new SqlConnection(conn);
SqlCommand cmd = new SqlCommand();
SqlDataAdapter sd = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
cmd.Connection = sqcon;
cmd.CommandText = "sps_selectemp";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
sqcon.Open();
sd.Fill(dt);
sqcon.Close();
List<EmployeeDetails> StudentList = new List<EmployeeDetails>();
foreach (DataRow dr in dt.Rows)
{
EmployeeDetails st = new EmployeeDetails();
st.ID = Convert.ToInt32(dr["EmpID"]);
st.FirstName = dr["FirstName"].ToString();
st.SecondName = dr["SecondName"].ToString();
st.Email = dr["Email"].ToString();
st.Gender = dr["Gender"].ToString();
st.Mobile = dr["Mobile"].ToString();
st.State = dr["State"].ToString();
st.City = dr["City"].ToString();
st.Country = dr["Country"].ToString();
StudentList.Add(st);
}
return View(StudentList.ToList());
}
Then i have added a view for corresponding view
#model List<webkendo.Models.EmployeeDetails>
#(Html.Kendo().Grid<webkendo.Models.EmployeeDetails>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(c => c.FirstName);
columns.Bound(c => c.SecondName);
columns.Bound(c => c.Email);
columns.Bound(c => c.Gender).Width(150);
})
.HtmlAttributes(new { style = "height: 550px;" })
.Scrollable()
.Groupable()
.Sortable()
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("getusers", "Home"))
.PageSize(20)
)
)
Still tried different methods
public List<EmployeeDetails> getusers()
{
SqlConnection sqcon = new SqlConnection(conn);
SqlCommand cmd = new SqlCommand();
SqlDataAdapter sd = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
cmd.Connection = sqcon;
cmd.CommandText = "sps_selectemp";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
sqcon.Open();
sd.Fill(dt);
sqcon.Close();
List<EmployeeDetails> StudentList = new List<EmployeeDetails>();
foreach (DataRow dr in dt.Rows)
{
EmployeeDetails st = new EmployeeDetails();
st.ID = Convert.ToInt32(dr["EmpID"]);
st.FirstName = dr["FirstName"].ToString();
st.SecondName = dr["SecondName"].ToString();
st.Email = dr["Email"].ToString();
st.Gender = dr["Gender"].ToString();
st.Mobile = dr["Mobile"].ToString();
st.State = dr["State"].ToString();
st.City = dr["City"].ToString();
st.Country = dr["Country"].ToString();
StudentList.Add(st);
}
return StudentList;
}
What am i doing wrong
First, decide if you are going to fetch all your data server side and present it in the grid, or if you are going to use AJAX with paging, etc. which is better for longer lists. You are trying to do both.
For the first, you need to get rid of the Read and set ServerOperation(false):
// Your model is the list of data
#(Html.Kendo().Grid(Model)
...
// Tell kendo you are providing the data
.DataSource(dataSource => dataSource
.Ajax()
.ServerOperation(false)
.PageSize(20)
// No Read since you provide all the data up front
)
For the second option:
// Tell kendo the type you are going to fetch in the Read
#(Html.Kendo().Grid<EmployeeDetails>()
...
// Tell kendo you want data retrieved via AJAX
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("getusers", "Home"))
.PageSize(20)
)
Now create your read action to return JSON and take advantage of Kendo's DataSourceRequest that handles paging, filtering, sorting, etc.
public JsonResult getusers([DataSourceRequest] DataSourceRequest request)
{
// The AJAX generally works with IQueryables so that it can select a
// page full or records at a time. Entity Framework makes this easy.
// You would need to amend for ADO.NET with stored proc.
var employees = _db.Employees;
DataSourceResult response = employees.ToDataSourceResult(request);
return Json(response, JsonRequestBehavior.AllowGet);
}

How to batch get items using servicestack.aws PocoDynamo?

With Amazon native .net lib, batchget is like this
var batch = context.CreateBatch<MyClass>();
batch.AddKey("hashkey1");
batch.AddKey("hashkey2");
batch.AddKey("hashkey3");
batch.Execute();
var result = batch.results;
Now I'm testing to use servicestack.aws, however I couldn't find how to do it. I've tried the following, both failed.
//1st try
var q1 = db.FromQueryIndex<MyClass>(x => x.room_id == "hashkey1" || x.room_id == "hashkey2"||x.room_id == "hashkey3");
var result = db.Query(q1);
//2nd try
var result = db.GetItems<MyClass>(new string[]{"hashkey1","hashkey2","hashkey3"});
In both cases, it threw an exception that says
Additional information: Invalid operator used in KeyConditionExpression: OR
Please help me. Thanks!
Using GetItems should work as seen with this Live Example on Gistlyn:
public class MyClass
{
public string Id { get; set; }
public string Content { get; set; }
}
db.RegisterTable<MyClass>();
db.DeleteTable<MyClass>(); // Delete existing MyClass Table (if any)
db.InitSchema(); // Creates MyClass DynamoDB Table
var items = 5.Times(i => new MyClass { Id = $"hashkey{i}", Content = $"Content {i}" });
db.PutItems(items);
var dbItems = db.GetItems<MyClass>(new[]{ "hashkey1","hashkey2","hashkey3" });
"Saved Items: {0}".Print(dbItems.Dump());
If your Item has both a Hash and a Range Key you'll need to use the GetItems<T>(IEnumerable<DynamoId> ids) API, e.g:
var dbItems = db.GetItems<MyClass>(new[]{
new DynamoId("hashkey1","rangekey1"),
new DynamoId("hashkey2","rangekey3"),
new DynamoId("hashkey3","rangekey4"),
});
Query all Items with same HashKey
If you want to fetch all items with the same HashKey you need to create a DynamoDB Query as seen with this Live Gistlyn Example:
var items = 5.Times(i => new MyClass {
Id = $"hashkey{i%2}", RangeKey = $"rangekey{i}", Content = $"Content {i}" });
db.PutItems(items);
var rows = db.FromQuery<MyClass>(x => x.Id == "hashkey1").Exec().ToArray();
rows.PrintDump();

Rewrite code for Automapper v5.0 to v4.0

Automapper v4.0 was very straight forward to use within a method, can someone help rewrite this for v5.0 please (specifically the Mapper code):
public IEnumerable<NotificationDto> GetNewNotifications()
{
var userId = User.Identity.GetUserId();
var notifications = _context.UserNotifications
.Where(un => un.UserId == userId && !un.IsRead)
.Select(un => un.Notification)
.Include(n => n.Gig.Artist)
.ToList();
Mapper.CreateMap<ApplicationUser, UserDto>();
Mapper.CreateMap<Gig, GigDto>();
Mapper.CreateMap<Notification, NotificationDto>();
return notifications.Select(Mapper.Map<Notification, NotificationDto>);
}
UPDATE:
It seems that EF Core doesn't project what AutoMapper is mapping with:
return notifications.Select(Mapper.Map<Notification, NotificationDto>);
But I do get results in Postman with the following code:
return notifications.Select(n => new NotificationDto()
{
DateTime = n.DateTime,
Gig = new GigDto()
{
Artist = new UserDto()
{
Id = n.Gig.Artist.Id,
Name = n.Gig.Artist.Name
},
DateTime = n.Gig.DateTime,
Id = n.Gig.Id,
IsCancelled = n.Gig.IsCancelled,
Venue = n.Gig.Venue
},
OriginalVenue = n.OriginalVenue,
OriginalDateTime = n.OriginalDateTime,
Type = n.Type
});
If you want to keep using static instance - the only change is in mapper initialization:
Mapper.Initialize(cfg =>
{
cfg.CreateMap<ApplicationUser, UserDto>();
cfg.CreateMap<Gig, GigDto>();
cfg.CreateMap<Notification, NotificationDto>();
});
Also you should run this code only once per AppDomain (somewhere on startup for example) and not every time you calling GetNewNotifications.

MVC 5 implicit conversion exists

I have a repository that I am tring to get a query to pass to a controller.
public ProjectViewModel SearchContractors(string zip)
{
var query = (from h in repository.tblHandymen
join hc in repository.tblHandyManCoverages on h.handymanID equals hc.handymanID
join s in repository.tblServiceRequests on hc.zip equals s.zip
where hc.zip == zip
where h.handymanID == hc.handymanID
where h.status == "Active"
select h
);
ProjectViewModel model = new ProjectViewModel
{
ContractorSearch = query.AsEnumerable()
};
return model;
}
Where I am stuck is here
ProjectViewModel model = new ProjectViewModel
{
ContractorSearch = query.AsEnumerable()
};
The error is an implicit conversion exists. Tried several things. Nothing working.
Your query is not returning a collection of ProjectContractorSearchViewModel objects (its returning a collection of tblHandymen). You need to project the results to typeof ProjectContractorSearchViewModel
var query = (from h in repository.tblHandymen
.....
).Select(x => new ProjectContractorSearchViewModel
{
someProperty = x.someProperty,
anotherProperty = x.anotherProperty,
....
});
ProjectViewModel model = new ProjectViewModel
{
ContractorSearch = query.AsEnumerable()
};
return model;

Changing content of MvxPickerViewModel

I am writing a simple application that contains a database of items. The items have a type, manufacturer, model, and a few other properties. I have a implemented three UIPickerView's with MvxPickerViewModel's as outlined in N=19 of the N+1 series for MvvmCross. There is one UIPickerView/MvxPickerViewModel for each the type, the manufacturer, and the model (only one is ever on the screen at a time). However if I update the ItemSource data for a MvxPickerViewModel, the rows that were already visible in the UIPickerView do not refresh until they are scrolled off the screen. The N=19 example, does not update the list of items in the UIPickerView so it isn't clear that the problem didn't exist there. Have I made a mistake or has anyone else experienced this? Is there a work around?
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
NavigationController.NavigationBarHidden = true;
var comparableTableViewSource = new MvxStandardTableViewSource(ComparableLV);
ComparableLV.Source = comparableTableViewSource;
var ManufacturerPicker = new UIPickerView();
var manufacturerPickerModel = new MvxPickerViewModel(ManufacturerPicker);
ManufacturerPicker.Model = manufacturerPickerModel;
ManufacturerPicker.ShowSelectionIndicator = true;
ManufacturerTextField.InputView = ManufacturerPicker;
var ModelPicker = new UIPickerView();
var modelPickerModel = new MvxPickerViewModel(ModelPicker);
ModelPicker.Model = modelPickerModel;
ModelPicker.ShowSelectionIndicator = true;
ModelTextField.InputView = ModelPicker;
var TypePicker = new UIPickerView();
var typePickerModel = new MvxPickerViewModel(TypePicker);
TypePicker.Model = typePickerModel;
TypePicker.ShowSelectionIndicator = true;
TypeTextField.InputView = TypePicker;
var set = this.CreateBindingSet<FirstView, FirstViewModel>();
set.Bind(comparableTableViewSource).For(s => s.ItemsSource).To(vm => vm.Comparables);
set.Bind(manufacturerPickerModel).For(p => p.ItemsSource).To(vm => vm.Manufacturers);
set.Bind(manufacturerPickerModel).For(p => p.SelectedItem).To(vm => vm.SelectedManufacturer);
set.Bind(ManufacturerTextField).To(vm => vm.SelectedManufacturer);
set.Bind(modelPickerModel).For(p => p.ItemsSource).To(vm => vm.Models);
set.Bind(modelPickerModel).For(p => p.SelectedItem).To(vm => vm.SelectedModel);
set.Bind(ModelTextField).To(vm => vm.SelectedModel);
set.Bind(typePickerModel).For(p => p.ItemsSource).To(vm => vm.Types);
set.Bind(typePickerModel).For(p => p.SelectedItem).To(vm => vm.SelectedType);
set.Bind(TypeTextField).To(vm => vm.SelectedType);
set.Apply();
var g = new UITapGestureRecognizer(() => {
HornTextField.ResignFirstResponder();
ManufacturerTextField.ResignFirstResponder();
ModelTextField.ResignFirstResponder();
});
View.AddGestureRecognizer(g);
}
Looking at MvxPickerViewModel.cs I'm suspicious that there is no call to ReloadAllComponents (or to ReloadComponent[0]) when the ItemsSource itself changes, but there is a call when the Collection internally changes.
As a workaround, perhaps try a subclass like:
public class MyPickerViewModel
: MvxPickerViewModel
{
private readonly UIPickerView _pickerView;
public MyPickerViewModel(UIPickerView pickerView)
: base(pickerViww)
{
_pickerView = pickerView;
}
[MvxSetToNullAfterBinding]
public override IEnumerable ItemsSource
{
get { return base.ItemsSource; }
set
{
base.ItemsSource = value;
if (value != null)
_pcikerView.ReloadComponent(0);
}
}
}
Would also be great to get a fix back into MvvmCross...

Resources