The SPListItem being updated was not retrieved with all taxonomy fields - content-type

I have added document library template using VS 2012. and then added custom content types to this library. the content types includes 3 managed metadata fields. After deploying the project when I add terms to taxonomy fields in document library, I got following error:
"The SPListItem being updated was not retrieved with all taxonomy fields"
I could not find any solution. Any body have an idea whats wrong ?

In the ELEMENTS.XML file of the contenttype your field (actually you need TWO, note how they are linked togheter) must be something like:
<Field Type="Note"
ID="{4B53F593-CF60-40DF-AEAF-23155BB9AA3F}"
DisplayName="_Circular_Tags"
Name="Circular_Tags_NOTE"
StaticName="Circular_Tags_NOTE"
ShowInViewForms="FALSE"
Required="FALSE"
Hidden="TRUE"
CanToggleHidden="TRUE"
RowOrdinal="0">
</Field>
<Field Type="TaxonomyFieldTypeMulti"
ID="{DF553026-F699-456F-AA24-0C6087DBE885}"
Name="Circular_Tags"
StaticName="Circular_Tags"
DisplayName="Circular_Tags_DisplayName"
Description="Circular_Tags_Description"
ShowField="Circular_Tags_Path"
Required="FALSE"
Sortable="FALSE"
AllowDeletion="TRUE"
EnforceUniqueValues="FALSE"
ShowInViewForms="TRUE"
Group="MyContentTypes_Group">
<Default></Default>
<Customization>
<ArrayOfProperty>
<Property>
<Name>TextField</Name>
<Value xmlns:q6="http://www.w3.org/2001/XMLSchema" p4:type="q6:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">{4B53F593-CF60-40DF-AEAF-23155BB9AA3F}</Value>
</Property>
</ArrayOfProperty>
</Customization>
</Field>
Then you need (in the feature-activated code) do the following:
SPSite site = properties.Feature.Parent as SPSite;
Guid fieldId = new Guid("{DF553026-F699-456F-AA24-0C6087DBE885}");
if (site.RootWeb.Fields.Contains(fieldId))
{
TaxonomySession session = new TaxonomySession(site);
if (session.TermStores.Count != 0)
{
var termStore = session.TermStores["ManagedMetadata_Proxy"];
var group = termStore.Groups["GroupName"];
var termSet = group.TermSets["TermSetName"];
TaxonomyField field = site.RootWeb.Fields[fieldId] as TaxonomyField;
//set the text field to the id of the _Circular_Tags field : 4B53F593-CF60-40DF-AEAF-23155BB9AA3F
field.TextField = new Guid("{4B53F593-CF60-40DF-AEAF-23155BB9AA3F}");
// Connect to MMS
field.SspId = termSet.TermStore.Id;
field.TermSetId = termSet.Id;
field.TargetTemplate = string.Empty;
field.AnchorId = Guid.Empty;
field.Update();
}
}
Finally in the SCHEMA.XML file in the List definition you should have a definition like this for the field:
<Field Type="TaxonomyFieldType" ID="{DF553026-F699-456F-AA24-0C6087DBE885}" Name="Circular_Tags" StaticName="Circular_Tags" DisplayName="Circular_Tags_DisplayName" Description="Circular_Tags_Description" ShowField="Circular_Tags_Path" Mult="TRUE" Required="FALSE" Sortable="FALSE" AllowDeletion="TRUE" EnforceUniqueValues="FALSE" ShowInViewForms="TRUE" Group="ContentTypes_Group">
<Default></Default>
<Customization>
<ArrayOfProperty>
<Property>
<Name>TextField</Name>
<Value xmlns:q6="http://www.w3.org/2001/XMLSchema" p4:type="q6:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">{4B53F593-CF60-40DF-AEAF-23155BB9AA3F}</Value>
</Property>
</ArrayOfProperty>
</Customization>
</Field>

Related

How to set visibility for actions for specific user groups in Alfresco

I am new in Alfresco, and currently I am working on small project. The problem that I have is that I need to set one action from multi-select to be visiable just for one user group. This action is on Search window, and it's download action.
(Picture attached)
I read that we can use Evaluators, but I am not sure how to do that.
This is my code inside xml:
<config evaluator="string-compare" condition="DownloadAll">
<multi-select>
<action type="action-link" id="onDownloadAllDocumentAsZip" icon="document-download"
label="action.download.all.as.zip.label" />
<action type="action-link" id="onDownloadAllAsExcel" icon="document-download"
label="action.download.all.as.excel.label" />
<action type="action-link" id="onDownloadAllStudyNotificationAsExcel" icon="document-download"
label="action.download.all.study.notification.as.excel.results.label" />
<action type="action-link" id="onDownloadAllAsExcelIUCLID" icon="document-download"
label="action.download.all.as.excel.iuclid.label" />
<action type="action-link" id="onDownloadAllAsExcelUpdateMetadata" icon="document-download"
label="action.download.all.as.excel.update.metadata.label" />
</multi-select>
</config>
I would have to introduce Evaluators or something like that on last action inside this multi-select.
Thanks in advance!
Yes, evaluator in share-config-custom.xml is the right way. Check some documentation https://docs.alfresco.com/content-services/latest/develop/share-ext-points/evaluators/. Simply you add tag <evaluator> inside <action> for example:
<action type="action-link" id="onDownloadAllAsExcelUpdateMetadata" icon="document-download" label="action.download.all.as.excel.update.metadata.label">
<evaluator>my.evaluator.doclib.action.isAdmin</evaluator>
</action>
Name of evaluator have to be set properly set in file /share/src/main/resources/alfresco/web-extension/yourprefix-share-slingshot-application-context.xml.
Take inspiration in this file with default settings https://github.com/Alfresco/share/blob/master/share/src/main/resources/alfresco/slingshot-documentlibrary-context.xml You can make lot of combinations via Predefined evaluators https://docs.alfresco.com/content-services/latest/develop/reference/share-document-library-ref/ If you wont be able make evaluator for specific group, write own java in path
share/src/main/java/your_packages/share/web/extesibility. This is how look my IsAdminEvaluator:
public class IsAdminEvaluator extends org.alfresco.web.evaluator.BaseEvaluator
{
public IsAdminEvaluator() {}
public boolean evaluate(JSONObject jsonObject)
{
RequestContext rc = org.springframework.extensions.surf.support.ThreadLocalRequestContext.getRequestContext();
User user = rc.getUser();
return (user != null) && (user.isAdmin());
}
}
and bean in yourprefix-share-slingshot-application-context.xml.
<bean id="my.evaluator.doclib.action.isAdmin" class="your_packages.share.web.extesibility.IsAdminEvaluator" />
If you need call some repo webscript use this.
final RequestContext rc = ThreadLocalRequestContext.getRequestContext();
final Connector conn = rc.getServiceRegistry().getConnectorService().getConnector("alfresco", rc.getUserId(), ServletUtil.getSession());
// Get nodeRef
final String nodeRef = (String) jsonObject.get("nodeRef");
if (nodeRef == null) {
return false;
}
// Create a Pattern object
Pattern r = Pattern.compile("^(.*):\\/(\\/.*)(\\/.*)$");
// Create matcher object
Matcher m = r.matcher(nodeRef.toString());
final Response response = conn.call("/signia/parent?nodeRef=" + m.group(0));
So in the worst way you can call /people/{personId}/groups webscript and look if users is in your group. But I think you can make solution from Predefined evaluators. I hope this help you ;)

Simple 1-N FK relationship woes

I'm trying to get a simple 1-N FK relationship working with DataNucleus JDO. I have classes GridDO and GridColumnDO with relevant getters and setters. I'm trying to establish that a grid has multiple columns. The entity_attribute (GridColumn) table has a FK column (named entity_id) to the entity (Grid) table's PK (also named entity_id). I worked off of the example code on the DataNucleus website. I can load the GridDO object, but when I try to get the columns, I get
Iteration request failed : SELECT 'com.mycompany.myapplication.data.GridColumnDO' AS NUCLEUS_TYPE,A0.DISPLAY_NAME,A0.COLUMN_ORDER,A0.PROPERTY_NAME,A0.ENTITY_ID,A0.ENTITY_ATTRIBUTE_ID,A0.VALUE_TYPE FROM ENTITY_ATTRIBUTE A0 WHERE A0.ENTITY_ID = ?
org.datanucleus.exceptions.NucleusDataStoreException: Iteration request failed : SELECT 'com.mycompany.myapplication.data.GridColumnDO' AS NUCLEUS_TYPE,A0.DISPLAY_NAME,A0.COLUMN_ORDER,A0.PROPERTY_NAME,A0.ENTITY_ID,A0.ENTITY_ATTRIBUTE_ID,A0.VALUE_TYPE FROM ENTITY_ATTRIBUTE A0 WHERE A0.ENTITY_ID = ?
...
Caused by: java.sql.SQLException: Parameter #1 has not been set.
Does anybody know what I might be doing wrong? I've been searching and banging at this for a while now, with no real luck. This is an excerpt from package-mssql.orm:
<class name="GridDO" identity-type="application" table="entity">
<field name="id" primary-key="true">
<column name="entity_id"/>
</field>
<field name="columns">
<collection element-type="com.mycompany.myapplication.data.GridColumnDO"/>
<element column="entity_id"/>
</field>
...
</class>
<class name="GridColumnDO" identity-type="application" table="entity_attribute">
<field name="id" primary-key="true">
<column name="entity_attribute_id"/>
</field>
...
</class>
The issue was that PersistenceCapable and PrimaryKey must either both be identified via annotations or both be identified via metadata. I had PersistenceCapable in an annotation and PrimaryKey in my .orm file.

get auto-genearated key for the inserted record in mybatis

I am working under a web application which use spring mvc + mybatis + mysql.
And I found that I can not get the auto-generated key for the last inserted record (I have googled so much).
This is the related configuration(take the model 'Post' for example):
spring.xml:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
//omitted
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="config.xml" />
</bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
mybatis config.xml
<configuration>
<typeAliases>
<typeAlias alias="Post" type="com.king.model.Post" />
</typeAliases>
<mappers>
<mapper resource="com/king/model/PostMapper.xml" />
</mappers>
</configuration>
PostMapper.xml:
<mapper namespace="com.king.model.PostMapper">
<insert id="insert" parameterType="Post">
insert into posts (title,body,created_at,updated_at) values (#{title},#{body},#{createDate},#{updateDate})
</insert>
</mapper>
Dao:
public abstract class AbstractSimpleDaoImpl<T> extends SqlSessionDaoSupport{
#Override
public int add(T entity) {
return getSqlSession().insert(getMapperNamespace() + ".insert", entity);
}
protected abstract String getMapperNamespace();
}
public class PostDao extends AbstractSimpleDaoImpl<Post> {
#Override
protected String getMapperNamespace() {
return "com.king.model.PostMapper";
}
}
However,when I insert a new Post to database:
postDao.add(post);
I can not get the generated id for the inserted post. I always get 1. I know this is the row-affected number.
Also,I read the mybatis guide,and I tried this:
<insert id="insert" parameterType="Post" useGeneratedKeys="true" keyProperty="id">
But it seems that,this does not work.
How to fix it?
In fact the following works:
<insert id="insert" parameterType="Post" useGeneratedKeys="true" keyProperty="id">
postDao.add(post);
will return 1 as before,but post.getId() will get the key.
This can be done using annotations as well.
final String INSERT = "insert into posts (title,body,created_at,updated_at) values (#{title},#{body},#{createDate},#{updateDate})";
#Insert(INSERT)
#Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
void insert(Post post) throws Exception;
Set keyProperty as the Java variable name.
Set keyColumn as the column name in the database.
After insert, post.getId() will have your generated ID.
Try using the following code; I added the keyColumn field to your code:
<insert id="insert" parameterType="Post" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
Alternatively, if you are using PostgreSql:
<insert id="insert" parameterType="Post" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
<selectKey keyProperty="id" resultType="java.lang.Integer">
SELECT
currVal('your_tbl_seq') as id
</selectKey> </insert>
This will work for Spring Boot using annotations and getting the id as a return value as in your original question.
#Insert("insert into sources (host, created_at) values (#{host}, now())")
#SelectKey(statement="select LAST_INSERT_ID()", keyProperty="id", before=false, resultType=long.class)
long create(#Param("host") String host);
Then long id = sourceMapper.create("abc"); would return your primary key.

Add items programmatically to repeatable items

How can I add an item to a repeatable property programmatically in c#:
let's say I have a node (node id 1234) and in it companies list property, where each item has comapny name and image (media picker).
how do I add an item programmtically ?
Here's what I have so far:
XPathNodeIterator xpathIterator = umbraco.library.GetXmlNodeById(NodeId.ToString());
XElement node = XElement.Parse(xpathIterator.Current.OuterXml);
var list = node.Descendants(propertyAlias).FirstOrDefault();
// how do I add items here ? something like:
list.Descendants().Add(...)
thanks.
The package I'm referring to is:
Repeatable Custom Content
update:
I think the solution is to update the xml in umbraco.config.
I have the following xml in umbraco.config:
<Companies id="1176" parentID="1447" ...>
<umbracoNaviHide>0</umbracoNaviHide>
<companyList>
<item>
<data alias="title">Company1</data>
<data alias="image" />
<data alias="text" />
<data alias="date" />
</item>
<item>
<data alias="title">Company2</data>
<data alias="image">1943</data>
<data alias="text" />
<data alias="date" />
</item>
</items>
</companyList>
</Companies>
I am able to update umbraco.config programmatically, but the results are not updated in the backend, so that when I publish the companies node again, the changes are deleted. How can I update the umbraco.config and publish the node ?
Maybe I sh should update the database directly instead ?
My code:
Document companiesDoc = new Document(COMPANIESNODEID);
XmlDocument document = content.Instance.XmlContent;
XmlNode n = document.SelectSingleNode("//Companies[#id=" + COMPANIESNODEID.ToString() + "]").SelectSingleNode("//items");
XmlNode newItem = document.CreateNode(XmlNodeType.Element, "item", null);
XmlNode dName = document.CreateNode(XmlNodeType.Element, "data", null);
XmlAttribute xn = document.CreateAttribute("alias");
xn.Value = "title";
dName.Attributes.Append(xn);
dName.InnerText = companyName;
XmlNode dImage = document.CreateNode(XmlNodeType.Element, "data", null);
XmlAttribute xi = document.CreateAttribute("alias");
xi.Value = "image";
dImage.Attributes.Append(xi);
dImage.InnerText = companyImage;
XmlNode dText = document.CreateNode(XmlNodeType.Element, "data", null);
XmlAttribute xt = document.CreateAttribute("alias");
xt.Value = "text";
dText.Attributes.Append(xt);
XmlNode dDate = document.CreateNode(XmlNodeType.Element, "data", null);
XmlAttribute xd = document.CreateAttribute("alias");
xd.Value = "date";
dDate.Attributes.Append(xd);
newItem.AppendChild(dName);
newItem.AppendChild(dImage);
newItem.AppendChild(dText);
newItem.AppendChild(dDate);
n.AppendChild(newItem);
I am able to update umbraco.config programmatically, but the results
are not updated in the backend, so that when I publish the companies
node again, the changes are deleted. How can I update the
umbraco.config and publish the node ?
You are going about it the wrong way. The umbraco.config file is a read-only XML representation of the Umbraco database that is generated by Umbraco and then cached. It isn't intended to be written to or accessed directly. Every time you publish a page in Umbraco this file is regenerated, hence the reasons your updates are not persisted.
You also don't want to try and write to the Umbraco database directly, either. It is very complex and requires lots of relations. Again, it isn't intended to be written to.
To update nodes directly what you really need to do is use the Umbraco Document API. This allows you direct write access to nodes which you can the programatically publish. Simple example:
Document doc = new Document(1234);
doc.getProperty("bodyText").Value = "<p>Your body text</p>";
doc.getProperty("articleDate").Value = DateTime.Now;
User author = User.GetUser(0);
doc.Publish(author);
umbraco.library.UpdateDocumentCache(doc.Id);
I'd suggest posting on http://our.umbraco.org/forum if you need more help.
I managed to solve the problem using this code:
var doc = new Document(COMPANIESNODEID);
XDocument xdoc = XDocument.Parse(doc.getProperty("companyList").Value.ToString());
xdoc.Element("items").Add(new XElement("item",
new XElement("data", new XAttribute("alias", "title"), companyName),
new XElement("data", new XAttribute("alias", "image"), companyImage)));
doc.getProperty("companyList").Value = xdoc.ToString();
doc.Save();
doc.Publish(new User(0));
umbraco.library.UpdateDocumentCache(doc.Id);

Incorrect component when querying immediately after insert using NHibernate

I have the following mapping for my table in MySql:
<class name="Tag, namespace" table="tags" >
<id name="id" type="Int32" unsaved-value="0">
<generator class="native"></generator>
</id>
<property name="name" type="String" not-null="true"></property>
<component name="record_dates" class="DateMetaData, namespace" >
<property name="created_at" type="DateTime" not-null="true"></property>
<property name="updated_at" type="DateTime" not-null="true"></property>
</component>
</class>
As you see the record_dates property is defined as a component field of type DateMetaDate. Both created_at and updated_at fields in 'tags' table are updated via triggers. Thus I can insert a new record like such:
var newTag = new Tag()
{
name = "some string here"
}
Int32 id = (Int32)Session.Save(tag);
Session.Flush();
ITag t = Session.Get<Tag>(id);
ViewData["xxx"] = t.name; // -----> not null
ViewData["xxx"] = t.record_dates.created_at; // -----> is null
However when querying the same record back immediately after it was inserted the record_dates field ends up null even though in the table those fields have got values.
Can any one please point out why the Session.Get ignores getting everything back from the table? is it because it caches the newly created record for which the records_dates is null? If so how can it be told to ignore the cached version?
Try using lazy="false" in your class tag:
<class name="Tag, namespace" table="tags" lazy="false">
As per my knowledge, the default behavior is to have lazy loading, which might not refresh your objects as needed.
The only I so far have found is to call Session.Clear() method on the NHibernate session object, which I guess forces NHibernate to fetch the record from the table again. But I'm afraid it removes everything in cache and thus be inefficient.
You can call ISession.Refresh(obj) to force the object to be reloaded from the database. My understanding is that this will not refresh all relationships, so if you need to reload the complete object graph, call ISession.Evict(obj) then ISession.Get(id) to remove it from the cache and reload it.

Resources