I have a DateTime field in my Entity, which needs to map to 2 separate fields in the ViewModel for date and time i.e.
// Entity
public partial class Event
{
public Int64 Id { get; set; }
public String Title { get; set; }
public DateTime StartDateTime { get; set; }
public DateTime EndDateTime { get; set; }
}
// ViewModel
public class EventAddEditViewModel
{
public Int64 Id { get; set; }
public String Title { get; set; }
public String StartDate { get; set; }
public String EndDate { get; set; }
public String StartTime { get; set; }
public String EndTime { get; set; }
}
Looking at this example, I have the following mapping:
Mapper.CreateMap<Event, EventAddEditViewModel>()
.ForMember(dest => dest.StartDate, opt => opt.MapFrom(src => src.StartDateTime.Date))
.ForMember(dest => dest.StartTime, opt => opt.MapFrom(src => src.StartDateTime.TimeOfDay))
.ForMember(dest => dest.EndDate, opt => opt.MapFrom(src => src.EndDateTime.Date))
.ForMember(dest => dest.EndTime, opt => opt.MapFrom(src => src.EndDateTime.TimeOfDay));
which is great. However, how do I reverse the mapping i.e. Mapper.CreateMap() so that it also maps when the form is POSTed?
I have done something similar to you, however I have StartDateTime as a DateTime Property on my ViewModel, and have two int properties for Hours and Minutes
e.g.
// ViewModel
public class EventAddEditViewModel
{
public Int64 Id { get; set; }
public String Title { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int StartHour { get; set; }
public int EndHour { get; set; }
public int StartMinute { get; set; }
public int EndMinute { get; set; }
}
This means that I can do the mapping thus
Mapper.CreateMap<Event, EventAddEditViewModel>()
.ForMember(dest => dest.StartDate, opt => opt.MapFrom(src => src.StartDateTime.Date))
.ForMember(dest => dest.StartHour, opt => opt.MapFrom(src => src.StartDateTime.Hour))
.ForMember(dest => dest.StartMinute, opt => opt.MapFrom(src => src.StartDateTime.Minute))
.ForMember(dest => dest.EndDate, opt => opt.MapFrom(src => src.StartDateTime.Date))
.ForMember(dest => dest.EndHour, opt => opt.MapFrom(src => src.EndDateTime.Hour))
.ForMember(dest => dest.EndMinute, opt => opt.MapFrom(src => src.StartDateTime.Minute));
Mapper.CreateMap<EventAddEditViewModel, Event>()
.ForMember(dest => dest.StartDateTime, opt => opt.MapFrom(src => new DateTime(src.StartDate.Year, src.StartDate.Month, src.StartDate.Day, src.StartHour, src.StartMinute, 0)))
.ForMember(dest => dest.EndDateTime, opt => opt.MapFrom(src => new DateTime(src.EndDate.Year, src.EndDate.Month, src.EndDate.Day, src.EndHour, src.EndMinute, 0)));
You should consider changing your viewmodel properties along those lines as integers will be easier to work with, however if they have to be strings, you'll need a way to parse out a DateTime object from your strings. Depending upon the format of your strings, something along these lines should work
Mapper.CreateMap<EventAddEditViewModel, Event>()
.ForMember(dest => dest.StartDateTime, opt => opt.MapFrom(src => DateTime.Parse( src.StartDate + " " + src.StartTime)))
.ForMember(dest => dest.EndDateTime, opt => opt.MapFrom(src => DateTime.Parse(src.EndDate + " " + src.EndTime)));
#StanK, I have simplier mapping syntax for this case:
Mapper.CreateMap<EventAddEditViewModel, Event>()
.ForMember(dest => dest.StartDateTime, opt => opt.MapFrom(src => src.StartDate.Add(src.StartTime.TimeOfDay)))
.ForMember(dest => dest.EndDateTime, opt => opt.MapFrom(src => src.EndDate.Add(src.EndTime.TimeOfDay)));
Related
I am finding it difficult to understand how the hierarchy is binded in the TreeList. We are trying to achieve InCell editing and I am unable to do it using the HTML MVC wrappers.
Please help me with the working solution as the one on the How to website does not give an insight on how the DB schema and am unable to debug it to understand how to structure the Model.
https://docs.telerik.com/aspnet-mvc/helpers/treelist/editing
Code snippets: I hope this helps:
Html Markup:
#(Html.Kendo().TreeList<ABC.Areas.COManager.ViewModels.MaterialViewModel>()
.Name("treelist")
.Toolbar(toolbar =>
{
//toolbar.Create().Name("Add Item to order");
toolbar.Save();
toolbar.Cancel();
})
.Columns(columns =>
{
columns.Add().Field(e => e.OrderItemId).Title("Item id").Expandable(true);//.Width(220);
columns.Add().Field(e => e.OrderSubItemId).Title("Sub item id");//.Width(220);
columns.Add().Field(e => e.WBS).Title("WBS");//.Width(220);
columns.Add().Field(e => e.Rate).Title("Rate");//.Width(100);
columns.Add().Field(e => e.Hours);
columns.Add().Field(e => e.CostAmount).Title("Cost Amount").Format("{0:C2}");
columns.Add().Command(c =>
{
c.CreateChild().Text("Add Item detail");
c.Destroy();
}
);//.Width(240);
})
.Events(ev => ev.DataBound("onDataBound"))
.Editable(e => e.Mode(TreeListEditMode.InCell))
.DataSource(dataSource => dataSource
.Batch(true)
.Read(read => read.Action("All_InCell", "OrderInputs"))
.Create(create => create.Action("Create_InCell", "OrderInputs").Type(HttpVerbs.Post))
.Update(update => update.Action("Update_InCell", "OrderInputs").Type(HttpVerbs.Post))
.Destroy(delete => delete.Action("Destroy_InCell", "OrderInputs").Type(HttpVerbs.Post))
.Model(m =>
{
m.Id(f => f.OrderSubItemId);
m.ParentId(f => f.OrderItemId);
//m.Expanded(true);
m.Field(f => f.OrderId);
m.Field(f => f.OrderItemId);
m.Field(f => f.OrderSubItemId);
m.Field(f => f.WBS);
m.Field(f => f.Rate);
m.Field(f => f.Hours);
m.Field(f => f.CostAmount).DefaultValue(0);
})
)
//.Height(540)
)
Controller action for read:
public JsonResult All_InCell([DataSourceRequest] DataSourceRequest request)
{
var result = GetDirectory().ToTreeDataSourceResult(request,
e => e.OrderSubItemId,
e => e.OrderItemId,
e => new MaterialViewModel
{
OrderItemId = e.OrderItemId,
OrderId = e.OrderId,
OrderSubItemId = e.OrderSubItemId,
OrderDate = e.OrderDate,
hasChildren = false
}
);
return Json(result, JsonRequestBehavior.AllowGet);
}
Gets the Data:
private IEnumerable<MaterialViewModel> GetDirectory()
{
return employeeDirectory.GetAll();
}
Returns the data (Dummy/Static): Could this be the problem? I am unsure.
internal IEnumerable<MaterialViewModel> GetAll()
{
var returnData = new List<MaterialViewModel>();
for (var i = 0; i <= 10; i++)
{
returnData.Add(new MaterialViewModel { OrderId = i + 1, OrderItemId = (10 * (i + 1)) + (i + 1), OrderSubItemId = (100 * (i + 1)) + (i + 1), OrderDate = DateTime.Now, WBS = "ABC" + (i + 1).ToString(), Description = "Description " + (i + 1).ToString(), });
}
return returnData;
}
Model:
MaterialViewModel
public class MaterialViewModel: OrderInputsViewModel
{
public string WBS { get; set; }
public string Description { get; set; }
public double Rate { get; set; }
public int Hours { get; set; }
public double CostAmount { get; set; }
}
Model:
OrderInputsViewModel
public class OrderInputsViewModel
{
//[ScaffoldColumn(false)]
public int? OrderId { get; set; }
//[ScaffoldColumn(false)]
public int OrderItemId { get; set; }
public int OrderSubItemId { get; set; }
public DateTime OrderDate { get; internal set; }
//[ScaffoldColumn(false)]
public bool hasChildren { get; set; }
}
Expected is to have a TreeList populated by the Model class and be able to create children in the loaded items.
Answered by the Progress Telerik support team. Sharing the resolution here in anticipation that it could help any future readers.
Ans - Perhaps the issue I was experiencing is that there is no data in the TreeList. The cause is that the ParentId is not nullable and that there are no root items - items with a ParentId which is null.
Making the following two changes, I am able to see the TreeList rendered correctly:
Model which is bonded to the TreeList:
public class OrderInputsViewModel
{
//Parent Id
**public int? OrderItemId { get; set; }**
Method that returns the data (Dummy/Static):
returnData.Add(new MaterialViewModel {
OrderId =i + 1 ,
OrderItemId = i % 2 == 0 ? (10 * (i + 1)) + (i + 1)
**: (int?)null**,
OrderSubItemId = (100 * (i + 1)) + (i + 1),
OrderDate = DateTime.Now,
WBS = "ABC" + (i + 1).ToString(),
Description = "Description " + (i + 1).ToString()
});
I have documents in a Mongo database, they use the _id field as an index.
I use Monstache to sync ES with Mongo's op log, so the documents in ES have the same _id field.
When searching a specific document, Kibana shows:
Tags:
tag1 testtag CreatedOn:
October 26th 2018, 14:25:57.053
_id:
FRaqDPIzWcVI2dl-oA9uUFHLVFQk8qIqqhySWSkM7Ds
_type:
testobject
_index:
test.object
_score:
0
but then a query with Nest, returns this in the Documents array:
_id = 0d5aa177-3066-4c6a-aaf5-9b887ae7297f
and when I look in the Hits array, I see:
Id = FRaqDPIzWcVI2dl-oA9uUFHLVFQk8qIqqhySWSkM7Ds
So in Documents, the _id is now an unrelated guid, but in Hits the _id is called Id and it has the right value.
Why is that, and is there a way to get the proper value for _id in Documents?
Edit: more info
This is the object; since it's shared by MongoDB and ES, it has attributes for both.
[Nest.ElasticsearchType, BsonIgnoreExtraElements]
public class TestObject
{
public string _id { get; set; }
public string OwnerId { get; set; }
public Flags Flags { get; set; }
[Nest.Text, BsonIgnoreIfDefault] public string Title { get; set; }
[Nest.Text] public string Tags { get; set; }
[Nest.Ignore] public string Hash { get; set; }
[Nest.Ignore, BsonIgnoreIfDefault] public string Link { get; set; }
}
This is the code creating the index:
private static void InitializeElasticSearch(string ConnectionString)
{
var Settings = new ConnectionSettings(new Uri(ConnectionString))
.DefaultIndex(_IndexName)
.DefaultFieldNameInferrer(_ => _)
.DefaultMappingFor<TestObject>(_ => _.Ignore(I => I._id));
_ElasticClient = new ElasticClient(Settings);
if (!_ElasticClient.IndexExists(_IndexName).Exists)
{
// create the index
var CreateIndexResponse = _ElasticClient.CreateIndex(_IndexName, C => C
.Settings(S => S
.Analysis(A => A
.CharFilters(Cf => Cf
.Mapping("expressions", E => E
.Mappings(TextLists.Expressions)
)
)
.TokenFilters(Tf => Tf
.Synonym("synonyms", Sy => Sy
.Synonyms(TextLists.Synonyms)
.Tokenizer("whitespace")
)
)
.Analyzers(An => An
.Custom("index", Ca => Ca
.CharFilters("expressions")
.Tokenizer("standard")
.Filters("standard", "synonyms", "stop")
)
)
)
)
.Mappings(M => M
.Map<TestObject>(Mm => Mm
.AutoMap()
.Properties(P => P
.Text(T => T
.Name(N => N.Title)
.Analyzer("index")
)
.Text(T => T
.Name(N => N.Tags)
.Analyzer("index")
)
)
)
)
);
Then, the query code:
var R = await _ElasticClient.SearchAsync<TestObject>(Sr => Sr
.Query(Q =>
{
// do we query 'all' ?
if (Terms == "*") return Q.MatchAll();
// or do we have a general query
return Q
.MultiMatch(Fu => Fu
.Fields(F => F
.Field(Ff => Ff.Tags)
.Field(Ff => Ff.Title)
)
.Query(Terms)
.Fuzziness(Fuzziness.EditDistance(2))
);
})
.Take(_MaxObjectReturned)
);
I have the following view.
#using BecomingAKendoUISamurai.ViewModels
<h2>Step 21 MVC Grid CRUD</h2>
<br/>
#(Html.Kendo().Grid<SamuraiViewModel>()
.Name("SamuraiGrid")
.Columns(columns =>
{
columns.Bound(m => m.Id).Hidden();
columns.Bound(m => m.FirstName);
columns.Bound(m => m.LastName);
columns.Bound(m => m.RankId).ClientTemplate("#=Rank#");
columns.Bound(m => m.DateOfBirth).Width(125);
columns.Bound(m => m.DateOfDeath).Width(125);
columns.Command(command => { command.Edit(); command.Destroy(); }).Width(200);
})
.DataSource(source => source
.Ajax()
.Sort(s => s.Add(p => p.LastName).Ascending())
.PageSize(5)
.Model(model =>
{
model.Id(m => m.Id);
})
.Create(create => create.Action(MVC.Home.ActionNames.CreateSamuraiMvc, MVC.Home.Name))
.Read(read => read.Action(MVC.Home.ActionNames.ReadSamuraiMvc, MVC.Home.Name))
.Update(update => update.Action(MVC.Home.ActionNames.UpdateSamuraiMvc, MVC.Home.Name))
.Destroy(destroy => destroy.Action(MVC.Home.ActionNames.DestroySamuraiMvc, MVC.Home.Name))
)
.Editable(editable => editable.Mode(GridEditMode.InLine)) //PopUp and InCell
.Sortable()
.Pageable(p => p.PageSizes(new int[]{2,4,6}))
.Filterable()
.ToolBar(toolbar => toolbar.Create())
)
Using the following View Model
namespace BecomingAKendoUISamurai.ViewModels
{
public class SamuraiViewModel : IMappableViewModel<SamuraiViewModel, Samurai>
{
#region Properties
public int Id { get; set; }
[Required]
[DisplayName("First Name")]
public string FirstName { get; set; }
[Required]
[DisplayName("Last Name")]
public string LastName { get; set; }
[Required]
[DisplayName("Rank")]
[UIHint("Rank")]
public int RankId { get; set; }
public string Rank { get; set; }
public List<SelectListItem> Ranks { get; set; }
[DisplayName("Date of Birth")]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}")]
[UIHint("DateOfBirthDate")]
public DateTime DateOfBirth { get; set; }
[DisplayName("Date of Death")]
[DisplayFormat(DataFormatString = "{0:MMMM dd yyyy}")]
[UIHint("DateOfDeathDate")]
public DateTime DateOfDeath { get; set; }
#endregion
#region Constructors
public SamuraiViewModel()
{
Ranks = new List<SelectListItem>();
}
public SamuraiViewModel(Samurai samurai)
{
FromEntity(samurai);
}
#endregion
#region IMappableViewModel
public void FromEntity(Samurai entity)
{
Mapper.CreateMap<Samurai, SamuraiViewModel>()
.ForMember(vm => vm.RankId, m => m.MapFrom(e => e.Rank))
.ForMember(vm => vm.Rank, m => m.MapFrom(e => e.Rank.ToString()));
Mapper.Map(entity, this);
}
public Samurai ToEntity()
{
var entity = new Samurai();
Mapper.CreateMap<SamuraiViewModel, Samurai>()
.ForMember(e => e.Rank, src => src.MapFrom(vm => vm.RankId));
Mapper.Map(this, entity);
return entity;
}
#endregion
public string JsonRanks
{
get { return Ranks.ConvertToJson(); }
}
}
}
Using the following editor template
#model DateTime?
#(Html.Kendo().DatePicker()
.Name("DateOfBirth")
.Format("MM/dd/yyyy")
.Value(Model == null ? DateTime.Now : #Model)
)
Calling the controller's read method
public virtual JsonResult ReadSamuraiMvc([DataSourceRequest] DataSourceRequest request)
{
return Json(GetSamuraiViewModels().ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
private List<SamuraiViewModel> GetSamuraiViewModels()
{
var viewModel = new List<SamuraiViewModel>();
var samurais = samuraiService.ReadSamurai().ToList();
if (samurais.Any())
{
samurais.ForEach(s => viewModel.Add(new SamuraiViewModel(s)));
}
return viewModel;
}
I can see all the data in the grid. For example row 1 has:
"Hatori" "Hanzo" "Grand Master" "03/15/1541" "April 16 1563" Edit Delete
When I click the Edit button, first name, last name and Rank all have the values defined in the row, but Date of Birth and Date of Death are both empty.
How do I fix this?
I have tried using inline and popup mode and get the same results.
Thanks in advance.
Try using DatePickerFor:
#model DateTime?
#(Html.Kendo().DatePickerFor(m => m)
.Format("MM/dd/yyyy")
)
I define my viewmodel called StockDataPoint and view like this,in the viewmodel I limit that the color's length is 5.In the grid,if I edit the color such as input the string 'green1' which length is larger than 5,and the grid show length no more than 5,but when I input the 'green',it should be OK,but the grid still show length no more than 5.I have update the new version such as kendo.all.min.js,jquery.min.js,but it still not work.THe project is here,and the picture is here
ViewModel:StockDataPoint
public class StockDataPoint
{
public DateTime Date { get; set; }
[StringLength(5, ErrorMessage = "length no more than 5")]
public string Color { get; set; }
public double Close { get; set; }
public int Volume { get; set; }
public double Open { get; set; }
public double High { get; set; }
public double Low { get; set; }
public string Symbol { get; set; }
}
View:grid to show and edit data
#(Html.Kendo().Grid<ChartServerGrouping.Models.StockDataPoint>()
.Name("DataGrid")
.Editable(editable => editable.Mode(GridEditMode.InLine))
.Columns(columns =>
{
columns.Bound(p => p.Close).Groupable(false).Title("Close").Width(120);
columns.Bound(p => p.Color).Groupable(false).Title("Color").Width(120);
columns.Command(command =>
{
command.Edit().UpdateText("Save");
}).Width(160); })
.Selectable(selectable => selectable.Type(GridSelectionType.Cell))
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("GetData", "Home"))
.Update(read => read.Action("GetData", "Home"))
.Model(model => model.Id(p => p.Date))
)
.AutoBind(true)
.Resizable(resize => resize.Columns(true)))
Yes,in the official web it is a bug.
I have a problem with many to many mapping with fluent in a mvc4 application,
when database (SQL2012Express) is create, the two tables to map aren't created.
I want to map in to many to many relation, because a product can be associated to many category and category can be many product. In my class Category I have :
public class Categoria : BaseEntity
{
public virtual string Name { get; set; }
public virtual ICollection<Prodotti> Prodotti { get; set; }
public Categoria()
{
Prodotti = new List<Prodotti>();
}
public virtual void AddProdotti(Prodotti pro)
{
Prodotti.Add(pro);
}
}
And in prduct class:
public class Prodotti:BaseEntity
{
public virtual string Name { get; set; }
public virtual ICollection<Categoria> Categoria { get; set; }
public virtual void AddCategorie(Categoria cat)
{
Categoria.Add(cat);
}
public Prodotti()
{
Categoria = new List<Categoria>();
}
}
The class map respectively are:
public class CategoriaMap : ClassMap<Categoria>
{
public CategoriaMap()
{
Id(x => x.Id).GeneratedBy.HiLo("Id");
Map(x => x.Name);
Map(x => x.Description);
Map(x => x.Active).Default("True");
HasManyToMany(x => x.Prodotti)
.Inverse()
.Table("CategoryProductsMap")
.ParentKeyColumn("CategoriaId").ChildKeyColumn("ProdottiId")
.Cascade.All(); ;
}
}
public class ProdottiMap :ClassMap<Prodotti>
{
public ProdottiMap()
{
Id(x=>x.Id).GeneratedBy.HiLo("Id");
Map(x => x.Name).Not.Nullable();
Map(x => x.Price).Precision(3);
Map(x => x.isFeatured).Nullable();
Map(x => x.ShortDescription);
Map(x => x.FullDescription);
Map(x => x.ShowOnHomePage).Nullable();
Map(x => x.Images);
Map(x => x.Published).Default("False");
Map(x => x.MetaDescription);
Map(x => x.MetaKeywords);
Map(x => x.MetaTitle);
Map(x => x.SeName);
Map(x => x.Deleted).Default("False");
Map(x => x.MinimumPurchaseCount);
Map(x => x.ShippingWeight);
Map(x => x.ShippingHeight);
Map(x => x.ShippingLength);
Map(x => x.ShippingWidth);
Map(x => x.CreatedOnUtc);
Map(x => x.UpdatedOnUtc);
HasManyToMany(x => x.Categoria)
.Table("CategoryProductsMap")
.ParentKeyColumn("ProdottiId").ChildKeyColumn("CategoriaId");
}
}
The configuration is:
var configuration =Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ShowSql().ConnectionString(c =>
c.FromConnectionStringWithKey("Connection1")))
.Mappings(m => m.FluentMappings
.AddFromAssemblyOf<latticinibufala.Entities.Maps.CustomerMap>() )
// Set session context class to enable ManagedWebSessionContext usage
.ExposeConfiguration(cfg => cfg.SetProperty("current_session_context_class", "managed_web"))
.ExposeConfiguration(cfg => cfg.SetProperty("adonet.batch_size", "10"))
.ExposeConfiguration(BuildSchema)
.BuildConfiguration()
;
sessionFactory = configuration.BuildSessionFactory();
What could be wrong?
Try adding following to your CategoriaMap constructor
Table("Categoria");
and following to ProdottiMap constructor
Table("Prodotti");
i have solved, the wrong line code is:
Map(x => x.Active).Default("True");
because the database want a number 1 = True
Just Add to you fuent-nHibernate configuration file
var props = new Dictionary<string, string>();
props.Add("query.substitutions", "true 1, false 0");
and then
.BuildConfiguration().AddProperties(props);