Perform model operations independent of metamodel
By using tags that can be set in the metamodel, model operations independent of metamodel class names and field names are possible.
Get field values by tag
To get fields using tagged values set in metamodel classes and fields, use the GetFieldValuesByFieldTag
method of the IModel
object. The values of all fields with tags set will be returned, so you can operate on the collection or get the first one with the LINQ FirstOrDefault
method.
public void GetFieldByTag(ICommandContext c, ICommandParams p)
{
IModel model = c.App.Workspace.CurrentModel;
var value = model.GetFieldValuesByFieldTag("SomeTag").FirstOrDefault();
if ( value is IModel)
{
//If it is a model, cast it with IModel
var valueModel = value as IModel;
c.App.Output.WriteLine("sample", $"Model: {valueModel.Name}");
}
else
{
//Otherwise, convert it to a string
c.App.Output.WriteLine("sample", $"Value: {value.ToString()}");
}
}
Extension method
It is convenient to define an extension method class like the following for tag access.
IModelExtension.cs
///<summary>
///Extension methods related to IModel
///</summary>
public static class IModelExtensions
{
///<summary>
///Gets the value of the specified field as a model.
///</summary>
///<param name="self">Target model. </param>
///<param name="field">Field name. </param>
///<returns> Retrieved model. If unable to retrieve, null. </returns>
public static IModel GetModel(this IModel self, string field)
{
return self.GetField(field) as IModel;
}
///<summary>
///Gets the model by the field tag.
///</summary>
///<param name="self">Target model. </param>
///<param name="fieldTag">The tag name of the field. </param>
///<returns>The retrieved model. If the model cannot be retrieved, this is null. </returns>
public static IModel GetModelByFieldTag(this IModel self, string fieldTag)
{
return self.GetFieldValuesByFieldTag(fieldTag).OfType<IModel>().FirstOrDefault();
}
///<summary>
///Gets a collection of models by the field's tag.
///</summary>
///<param name="self">The target model. </param>
///<param name="fieldTag">The field's tag. </param>
///<returns>The retrieved model collection. If the model cannot be retrieved, this is an empty collection. </returns>
public static IEnumerable<IModel> GetModelsByFieldTag(this IModel self, string fieldTag)
{
var ret = self.GetFieldValuesByFieldTag(fieldTag).OfType<IModel>();
if (ret == null)
{
return Enumerable.Empty<IModel>();
}
return ret;
}
///<summary>
///Gets the field information of the specified tag of the model.
///</summary>
///<param name="self">Target model. </param>
///<param name="fieldTag">Specified tag. </param>
///<returns>Field information. Null if not available. </returns>
public static IField GetFieldByFieldTag(this IModel self, string fieldTag)
{
return self.Metaclass.GetFieldsByTag(fieldTag).FirstOrDefault();
}
///<summary>
///Gets the field name of the specified tag.
///</summary>
///<param name="self">Target model. </param>
///<param name="fieldTag">Specified tag. </param>
///<returns>Field name. If not available, null. </returns>
public static string GetFieldNameByFieldTag(this IModel self, string fieldTag)
{
return self.GetFieldByFieldTag(fieldTag)?.Name;
}
///<summary>
///Checks whether the field of the specified tag is a model defined in the metamodel.
///</summary>
///<param name="self">Target model. </param>
///<param name="fieldTag">Specified tag. </param>
///<returns>True if defined, false otherwise. </returns>
public static bool HasFieldTag(this IModel self, string fieldTag)
{
return self.Metaclass.GetFieldsByTag(fieldTag).Any();
}
///<summary>
///Checks whether the model has a field with the specified tag defined in the metamodel.
///</summary>
///<param name="self">Target model. </param>
///<param name="fieldTags">Specified tags. Comma-separated list. </param>
///<returns>True if all are defined, false otherwise. </returns>
public static bool HasFieldTags(this IModel self, string fieldTags)
{
var fieldTagList = fieldTags.Split(',');
return HasFieldTags(self, fieldTagList);
}
///<summary>
///Checks whether the model has a field with the specified tag defined in the metamodel.
///</summary>
///<param name="self">Target model. </param>
///<param name="fieldTagList">Collection of the specified tags. </param>
///<returns>True if all are defined, false otherwise. </returns>
public static bool HasFieldTags(this IModel self, IEnumerable<string> fieldTagList)
{
foreach (var fieldTag in fieldTagList)
{
if (!self.Metaclass.GetFieldsByTag(fieldTag).Any())
{
return false;
}
}
return true;
}
///<summary>
///Gets the field value by the field's tag.
///</summary>
///<param name="self">The target model. </param>
///<param name="fieldTag">The field's tag. </param>
///<returns>The field value. Null if not available. </returns>
public static string GetFieldValueStringByTag(this IModel self, string fieldTag)
{
var ret = self.GetFieldValuesByFieldTag(fieldTag).FirstOrDefault();
return ret as string;
}
///<summary>
///Sets the field value using the field's tag.
///Does nothing if the field is not found.
///</summary>
///<param name="self">Target model. </param>
///<param name="fieldTag">Field tag. </param>
///<param name="value">Setting value. </param>
public static void SetFieldByTag(this IModel self, string fieldTag, object value)
{
var field = GetFieldByFieldTag(self, fieldTag);
if (field == null)
{
return;
}
self.SetField(field, value);
}
///<summary>
///Adds a new model with the tag of the field.
///Throws an exception if the field is not found.
///</summary>
///<param name="self">Target model. </param>
///<param name="fieldTag">Tag of the field. </param>
///<param name="className">Class name of the model to add. If not specified, the class of the field type will be used. </param>
public static IModel AddNewModelByFieldTag(this IModel self, string fieldTag, string className = null)
{
var field = self.GetFieldByFieldTag(fieldTag);
if (field == null)
{
throw new ArgumentException($"No field found for {fieldTag}");
}
if (className == null)
{
className = field.TypeClass.Name;
}
return self.AddNewModel(field.Name, className);
}
}