I've created a custom module called "Hospital" for the Advance Developer course project. In it, I've created a class named "Doctor" with DoctorID, DoctorName, DoctorEmail, DoctorSpecialty
When I attempt to make a new Doctor record via the module I'm given a SQL error.
Cannot insert the value NULL into column 'DoctorID', table 'Hospital.dbo.Hospital_Doctor'; column does not allow nulls.
Shouldn't the database automatically be set up to auto-incrememnt? Or did I miss a step. The DoctorID column is generated by the CMS, so I cannot customize it.
Yes, the system should automatically generate the ID. I'd try to create the custom class again, maybe something went wrong during the setup.
If you want to debug the issue you can try enabling the SQL profiler to see what SQL query gets executed. If you don't have a sufficient license to run the profiler, try using the built in Kentico SQL debug.
You also can check the Info/InfoProvider class code files to see if the class is setup correctly. Focus on the TypeInfo object, e.g. in the example below the OfficeID field is set to auto increment:
/// <summary>
/// Type information.
/// </summary>
#warning "You will need to configure the type info."
public static ObjectTypeInfo TYPEINFO = new ObjectTypeInfo(typeof(OfficeInfoProvider), OBJECT_TYPE, "OfficeOverview.Office", "OfficeID", "OfficeLastModified", "OfficeGuid", "OfficeName", "OfficeDisplayName", null, null, null, null)
{
ModuleName = "OfficeOverview",
TouchCacheDependencies = true,
};
Related
I have a requirement to get products by code without knowing catalogType. Is that possible to retrieve products without passing catalogType?
Below is the code snippet I've tried:
#Resource
private ProductDao productDao;
#Resource
private CatalogVersionService catalogVersionService;
List<ProductModel> getProductsByCode(String code) {
CatalogVersionModel catalogVersionModel = new CatalogVersionModel();
catalogVersionModel.setVersion("Online");
catalogVersionService.addSessionCatalogVersion(catalogVersionModel);
List<ProductModel> productModels = productDao.findProductsByCode(code);
}
Below is the exception am getting:
{
"errors": [
{
"message": "model CatalogVersionModel (<unsaved>) cannot be serialized due to being modified, new or removed",
"type": "FlexibleSearchError"
}
]
}
May I know how to fix for above issue?
When you create a product/variant in SAP Commerce (hybris) you must attach it to a catalog.
A catalog (CatalogModel) also have a version (usually staged or online), and the object is called a CatalogVersionModel
When you want to retrieve a product/variant, you must indicate the CatalogVersionModel because the product code is not a unique key to retrieve the product in the DB (you can check the Type "Product" in the backoffice and see in the XML pane that both code and catalogVersion have the value unique="true")
Now in you code there are several issue.
You should not create a catalog version but you should retrive it using a service (See DefaultCatalogVersionService)
You should use a service to retrieve your product (See DefaultProductService)
In productService implementation, you'll find two methods getProductForCode.
One with only the sku code as parameter
One with the sku code and catalogVersion as parameter
The first method actually looks like the method you want, but in fact, it uses the catalogVersion in your session. Your session will be different if you run your code in groovy or if you run your code in Java from your ecommerce website.
You can find the comment of this method below
Returns the Product with the specified code. As default the search uses the current session user, the currentsession language and the current active catalog versions (which are stored at the session in the attribute SESSION_CATALOG_VERSIONS).For modifying the search session context see FlexibleSearchQuery.
You need to specify the catalog, because it is possible to have multiple catalogs, and the same product could exist in all of those catalogs.
After I added versioning to a custom class (see https://devnet.kentico.com/articles/module-development-versioning-recycle-bin), the duplicated object is created (instead of just updating the existing one) when rollback feature is used.
Since I was asked for the exact steps that I took, here they are:
I have a custom class which is called StoreInfo. It contains a set of fields as Name, Address, Country, etc.
For enabling versioning, I added the following changes to the generated code:
public class StoreInfo : AbstractInfo<IndustryInfo>
{
...
public static ObjectTypeInfo TYPEINFO = new ObjectTypeInfo(...)
{
...
SupportsVersioning = true
};
...
protected override bool VersioningEnabled
{
get
{
return SettingsKeyInfoProvider.GetBoolValue("CMSEnableObjectsVersioning");
}
}
}
After this change was applied the Versions tab appeared in the UI interface:
Then I changed the name of the store from Test name to Test name 1, so Version 1.1 was added to the versions list:
The issue happened when I clicked this button:
Instead of updating the name of the existing Store back from Store name 1 to Store name it created a new store with the data of Version 1.0:
Any thoughts about why this happens would be helpful.
Kentico version is 11. (dev. approach - portal engine)
If you deleted Object 1 and then created a "new" Object 1 and tried to roll back the deletion of the original Object 1, it will create a new one because they don't have the same attributes, especially the GUID.
So you may need to specify exactly the steps you took when you deleted the object, what you did after you deleted the object and what you did when you rolled back the original object.
Suppose I create a model
public class Foo :TableEntity {
public int OriginalProperty {get;set;}
}
I then deploy a service that periodically updates the values of OriginalProperty with code similar to...
//use model-based query
var query = new TableQuery<Foo>().Where(…);
//get the (one) result
var row= (await table.ExecuteQueryAsync(query)).Single()
//modify and write it back
row.OriginalProperty = some_new_value;
await table.ExecuteAsync(TableOperation.InsertOrReplace(row));
At some later time I decide I want to add a new property to Foo for use by a different service.
public class Foo :TableEntity {
public int OriginalProperty {get;set;}
public int NewProperty {get;set;}
}
I make this change locally and start updating a few records from my local machine without updating the original deployed service.
The behaviour I am seeing is that changes I make to NewProperty from my local machine are lost as soon as the deployed service updates the record. Of course this makes sense in some ways. The service is unaware that NewProperty has been added and has no reason to preserve it. However my understanding was that the TableEntity implementation was dictionary-based so I was hoping that it would 'ignore' (i.e. preserve) newly introduced columns rather than delete them.
Is there a way to configure the query/insertion to get the behaviour I want? I'm aware of DynamicTableEntity but it's unclear whether using this as a base class would result in a change of behaviour for model properties.
Just to be clear, I'm not suggesting that continually fiddling with the model or having multiple client models for the same table is a good habit to get into, but it's definitely useful to be able to occasionally add a column without worrying about redeploying every service that might touch the affected table.
You can use InsertOrMerge instead of InsertOrReplace.
ReSharper 8.X ships with a macro that fetches the "Containing Type Name", but what I want to do is manipulate that name. I'm using this in a Visual Studio 2013 Web API project, and I want a template that takes the class name and builds the URL that has to be called. So, for example, suppose I have this:
public class AnnouncementController : ApiController
{
//Want to put a template here!
[HttpGet]
public HttpResponseMessage GetActiveAnnouncements()
{
/// ...
}
}
now my ReSharper template will look something like this:
/// This sample shows how to call the <see cref="$METHOD$"/> method of controller $CLASS$ using the Web API.
/// https://myurl.mydomain.com/api/$CONTROLLER$/$METHOD$
$Controller$, by convention, is the class name minus the letters 'Controller'. This is because ASP.NET MVC Web API projects expect classes derived from ApiController to end with the string 'Controller',
Since this class is AnnouncementController, the template should output
https://myurl.mydomain.com/api/Announcement/GetActiveAnnouncements
Resharper's Built-In Macros can give me some of what I need, but I want to write a custom macro that fetches the containing type name and chops "Controller" off of it. I would like to do that directly, without storing the containing type name in another parameter.
Also, how do I install this custom macro? I've Googled around, and all I found was a lot of dead links and old walkthroughs written for ReSharper version 7 and below that do NOT work with ReSharper 8.x
After a lot of fighting, here is my solution.
[MacroImplementation(Definition = typeof (ControllerNameMacroDefinition))]
public class ControllerNameMacroImplementation : SimpleMacroImplementation
{
public ControllerNameMacroImplementation([Optional] IReadOnlyCollection<IMacroParameterValueNew> arguments)
{
}
public override HotspotItems GetLookupItems(IHotspotContext context)
{
var ret = "CONTROLLER";
var fileName = GetFileName(context);
if (!fileName.IsNullOrEmpty())
{
//Replace "Controller.cs" in two separate steps in case the extension is absent
ret = fileName.Replace("Controller", "").Replace(".cs", "");
}
return MacroUtil.SimpleEvaluateResult(ret);
}
/// <summary>
/// Returns the filename of the current hotspot context
/// </summary>
private string GetFileName(IHotspotContext context)
{
var psiSourceFile = context.ExpressionRange.Document.GetPsiSourceFile(context.SessionContext.Solution);
return psiSourceFile == null ? string.Empty : psiSourceFile.Name;
}
}
I wanted to do exactly this, but for JavaScript Jasmine tests -- SomethingViewModel.js, with a fixture of SomethingViewModelFixture.js, but wanted to be able to refer to SomethingViewModel in the file. A few slight modifications to the above made it possible.
Unfortunately, there's a ton more things you need to do in order to get your plugin to actually install. Here's a list. I hope it's comprehensive.
NuGet package install JetBrains.ReSharper.SDK, make sure you have the correct version installed!
Copy your Class Library DLL to C:\Users\<you>\AppData\Local\JetBrains\ReSharper\<version>\plugins\<your plugin name>, creating the plugins directory if needed.
You need the plugin Annotations in your AssemblyInfo.cs file:
[assembly: PluginTitle("Your extensions for ReSharper")]
[assembly: PluginDescription("Some description")] -- this is displayed in ReSharper->Options->Plugins
[assembly: PluginVendor("You")]
You need a class in your project that defines the MacroDefinition, as well as the above MacroImplementation
[MacroDefinition("MyNamespace.MyClassName", ShortDescription = "A short description of what it does.", LongDescription = "A long description of what it does.")]
"ShortDescription" - this is displayed in the "Choose Macro" dialog list.
"LongDescription" you'd think this would be in the "Choose Macro" description, but it isn't.
I just added this annotation to the above file.
The file you add the MacroDefinition to needs to implement IMacroDefinition, which has a method (GetPlaceholder) and a property (Parameters) on it. The former can return any string ("a") and the latter can return an empty array.
You can ignore the WiX/NuGet stuff if you want. Just for a local install.
In VS, the ReSharper->Options->Plugins section has some troubleshooting details on why your plugin might not be loading.
Good luck!
After spending a year working with the Microsoft.Xrm.Sdk namespace, I just discovered yesterday the Entity.FormattedValues property contains the text value for Entity specific (ie Local) Option Set texts.
The reason I didn't discover it before, is there is no early bound method of getting the value. i.e. entity.new_myOptionSet is of type OptionSetValue which only contains the int value. You have to call entity.FormattedValues["new_myoptionset"] to get the string text value of the OptionSetValue.
Therefore, I'd like to get the crmsrvcutil to auto-generate a text property for local option sets. i.e. Along with Entity.new_myOptionSet being generated as it currently does, Entity.new_myOptionSetText would be generated as well.
I've looked into the Microsoft.Crm.Services.Utility.ICodeGenerationService, but that looks like it is mostly for specifying what CodeGenerationType something should be...
Is there a way supported way using CrmServiceUtil to add these properties, or am I better off writing a custom app that I can run that can generate these properties as a partial class to the auto-generated ones?
Edit - Example of the code that I would like to be generated
Currently, whenever I need to access the text value of a OptionSetValue, I use this code:
var textValue = OptionSetCache.GetText(service, entity, e => e.New_MyOptionSet);
The option set cache will use the entity.LogicalName, and the property expression to determine the name of the option set that I'm asking for. It will then query the SDK using the RetrieveAttriubteRequest, to get a list of the option set int and text values, which it then caches so it doesn't have to hit CRM again. It then looks up the int value of the New_MyOptionSet of the entity and cross references it with the cached list, to get the text value of the OptionSet.
Instead of doing all of that, I can just do this (assuming that the entity has been retrieved from the server, and not just populated client side):
var textValue = entity.FormattedValues["new_myoptionset"];
but the "new_myoptionset" is no longer early bound. I would like the early bound entity classes that gets generated to also generate an extra "Text" property for OptionSetValue properties that calls the above line, so my entity would have this added to it:
public string New_MyOptionSetText {
return this.GetFormattedAttributeValue("new_myoptionset"); // this is a protected method on the Entity class itself...
}
Could you utilize the CrmServiceUtil extension that will generate enums for your OptionSets and then add your new_myOptionSetText property to a partial class that compares the int value to the enums and returns the enum string
Again, I think specifically for this case, getting CrmSvcUtil.exe to generate the code you want is a great idea, but more generally, you can access the property name via reflection using an approach similar to the accepted answer # workarounds for nameof() operator in C#: typesafe databinding.
var textValue = entity.FormattedValues["new_myoptionset"];
// becomes
var textValue = entity.FormattedValues
[
// renamed the class from Nameof to NameOf
NameOf(Xrm.MyEntity).Property(x => x.new_MyOptionSet).ToLower()
];
The latest version of the CRM Early Bound Generator includes a Fields struct that that contains the field names. This allows accessing the FormattedValues to be as simple as this:
var textValue = entity.FormattedValues[MyEntity.Fields.new_MyOptionSet];
You could create a new property via an interface for the CrmSvcUtil, but that's a lot of work for a fairly simple call, and I don't think it justifies creating additional properties.